【发布时间】:2010-11-10 08:19:52
【问题描述】:
我想知道当从多个线程访问一个变量时,是否必须为每次访问都锁定它?例如,我有一个列表变量,并且希望在我从中删除项目时无法访问该列表。即使在仅访问数据的线程中也必须将其锁定,或者将其锁定在“删除项目”线程中就足够了。我担心的是,如果一个线程访问列表在进程中间停止,转到另一个从列表中删除并锁定变量的线程,则会出现错误。
【问题讨论】:
标签: c# multithreading
我想知道当从多个线程访问一个变量时,是否必须为每次访问都锁定它?例如,我有一个列表变量,并且希望在我从中删除项目时无法访问该列表。即使在仅访问数据的线程中也必须将其锁定,或者将其锁定在“删除项目”线程中就足够了。我担心的是,如果一个线程访问列表在进程中间停止,转到另一个从列表中删除并锁定变量的线程,则会出现错误。
【问题讨论】:
标签: c# multithreading
您的浴室门没有锁。相反,它有一个双面标志,一侧写着“已占用”,另一侧写着“未占用”。当有人接近浴室时,如果它被标记为占用,他们会等到它被标记为无人占用。如果它被标记为无人占用,他们将标志设置为占用并进入。当他们离开时,他们将标志设置回无人占用。
(还必须存在一些协商机制来处理有两个或更多人在等待的情况 - 谁先进来?还有,当两个人同时接近无人使用的浴室时会发生什么 - 谁赢了?但是我们将忽略这些皱纹;它们与类比无关。)
这个方案工作得很好。你的问题是“如果有人忽略了这个标志,或者忘记改变它,我会不会遇到同时有两个人在浴室里的情况?”
是的,显然你可以。如果你不相信我,那么我鼓励你在浴室里试一试,看看当有人无视协议时会发生什么。只有每个人都遵守该协议,资源访问协议才会保护对该资源的访问!
【讨论】:
如果您希望将集合保持在一致状态(或您使用锁保护的任何其他对象),则必须锁定读取和写入。
有一些“例外”,例如使用ReaderWriterSlimLock,您仍然需要获取写入锁,但您可以高效地执行多线程读取:
使用 ReaderWriterLockSlim 保护一个 被多个人读取的资源 线程并由一个线程写入 一次。 ReaderWriterLockSlim 允许 多个线程处于读取模式, 允许一个线程处于写模式 拥有锁的独占所有权, 并允许一个线程已读取 访问处于可升级读取模式, 线程可以从中升级到 写模式而不必 放弃其对 资源。
【讨论】:
ReaderWriterLockSlim 最终可能会比普通的旧 lock 慢。 RWLS 的开销大约是lock 的 5 倍,因此读者的数量必须大大超过写者的数量并且持有锁足够长的时间才能超过额外开销的盈亏平衡。这是一个很好的建议,值得一试,但如果它最终没有成功也不要感到惊讶。
我已经多次问过自己这个问题,并意识到当这个问题出现时,同步协议很可能被破坏了。在健全的同步规则中,甚至不会出现进行不受保护的访问的愿望。
我能想到的唯一例外是您有某种计数器,受锁保护,您只想检查它以用于统计/信息目的。如果这就是您感兴趣的全部,并且您知道对该计数器变量的读/写在您的特定平台和内存模型(以及该特定软件甚至可以远程运行的每个未来平台)上是原子的,那么请随意无需锁即可进入柜台。第二个前提条件无论如何都很难满足,所以你不应该这样做。
【讨论】:
在对象上使用lock 并不会真正锁定对象。锁定对象实际上只是一个标记,因此您可以锁定任何对象,只要所有线程都同意相同的锁定对象来读取和写入相关共享状态。约定是使用Object 的私有只读实例并锁定它。
【讨论】: