你的浴室门上没有锁,而是有一个双面标志,一面写着“占用”,另一面写着“未占用”。 当有人接近浴室时,如果标志被标记为“占用”,他们就等待直到标志标记为“未占用”。 如果标志被标记为“未占用”,他们将标志设置为“占用”并进入。 离开时,他们将标志设置回“未占用”。
(还必须存在一些协商机制来处理有两个或更多人等待的情况 - 谁先进去?而且,当两个人同时接近一个未占用的浴室时会发生什么 - 谁赢了?但我们将忽略这些细节;它们与类比不相关。)
这种方案完全可行。 你的问题是“如果有人忽略标志,或者忘记改变它,我会遇到两个人同时在浴室的情况吗?”
显然可以。如果你不相信我,那么我鼓励你尝试一下,看看当有人忽略协议时会发生什么。只有每个人都遵循协议,资源访问协议才能保护对该资源的访问!
使用ReaderWriterLockSlim来保护一个被多个线程读取并被单个线程写入的资源。ReaderWriterLockSlim允许多个线程处于读模式,允许一个线程处于写模式并独占锁,允许一个具有读访问权限的线程处于可升级读模式,从而该线程可以升级到写模式而无需放弃其对资源的读访问权限。
我已经问过自己这个问题几次,并意识到一旦出现这个问题,同步协议很可能被破坏。在良好的同步纪律中,甚至不会出现进行不受保护访问的欲望。
我所能想到的唯一例外是,您拥有由锁保护的某种计数器,并且您只想为统计/信息目的检查它。如果您只对此感兴趣,并且您知道对该计数器变量的读/写在您特定的平台和内存模型上是原子的(并且将来此特定软件即使在任何未来平台上运行时也是如此),则可以随意访问计数器而不使用锁定。第二个前提条件本来就很难满足,所以您不应该这样做。
在对象上使用lock
并不会真正锁定该对象。实际上,锁对象只是一种令牌,因此您可以锁定任何对象,只要所有线程都同意对共享状态的读写使用相同的锁定对象。约定是使用一个私有的只读Object
实例,并在其上进行锁定。
ReaderWriterLockSlim
可能比普通的lock
更慢。RWLS 的开销约为lock
的 5 倍,因此读者的数量必须显着超过写入者,并且保持足够长的时间才能超过额外开销的盈亏平衡点。这是一个好建议,值得尝试,但如果最终不起作用,请不要感到惊讶。 - Brian Gideon