C#多线程:获取必要的读锁定?

时间:2009-11-03 17:03:31

标签: c# multithreading

在从多个线程读取变量之前是否需要获取锁定?

12 个答案:

答案 0 :(得分:87)

简短的回答是:它取决于。

答案很长:

  • 如果它不是共享值,即只有一个线程可以看到它(或使用它),则不需要任何同步。

  • 如果它是一个不可变的值,即你只设置一次然后只读它,那么在没有同步的情况下这样做是安全的(只要你在第一次写入完成之前没有开始读取)

  • 如果它是最多32位的“原始”类型(例如byteshortint),则在阅读时可以获得陈旧(旧)数据。如果那不打扰你,你就定了。如果不希望使用陈旧数据,那么使变量volatile可以解决此问题而无需额外的读取同步。但如果您有赛车作家,则需要遵循与下面long相同的建议。

  • 如果它是长于32位的“原始”类型(例如longdecimaldouble),则需要同步,否则您可以读取“half”一个值,另一个的“一半”,并获得疯狂的结果。为此,推荐的方法是使用Interlocked类中的方法进行读写操作。

  • 如果它是引用类型,则需要同步以避免看到无效状态(Jeff Lamb的picture example是一个好的状态)。 lock语句可能就足够了。同样,您需要锁定读取和写入。

还有一些其他要点需要考虑(例如锁定多长时间),但我认为这些都足以回答你的问题。

答案 1 :(得分:11)

这取决于变量的类型和您的平台。例如,读取Int64s并不保证在32位计算机上是原子的。因此,Interlocked.Read

答案 2 :(得分:5)

如果在1个汇编指令中完成了值的加载,则无需锁定。您不关心10分钟前或1微秒前的值是否发生了变化。你现在只想要这个值。

但是,如果您正在加载巨大的数组或图片或其他东西,那么锁定它可能是个好主意。从理论上讲,您可以在加载数据时获得抢占,并拥有第一项的一半和第二项的一半。

如果它是一个简单的变量,就像bool或int一样,没有必要。

答案 3 :(得分:5)

根据以下答案,您还可以使用ReadWriterLockSlim执行读锁定。

这将允许您在读取时仅执行读锁定,并在修改变量时执行写入锁定。多个线程可以同时具有读锁定,但是一旦线程请求写锁定,所有新请求都将被阻止,直到它完成。

如果您进行大量读取而不是多次写入,这种锁定将非常有用。

与大多数多线程问题一样,研究它是否足以理解它是否真的适合您的问题,ReadWriterLock不适合所有锁定情况。

答案 4 :(得分:3)

阅读不需要锁定;只要你不关心阅读的“正确性”。如果你试图在没有锁定的情况下写作,那将是危险的。

答案 5 :(得分:3)

这取决于它是否是本地变量或共享变量,以及在此期间是否有其他内容可以写入,以及在阅读之后您将要做什么。

如果您根据变量做出决定,请考虑下一行代码可能基于现在陈旧的数据。

答案 6 :(得分:2)

如果是常数,不是。

如果它是可更新的值,是的,如果您需要一致性。

对于必须管理确切值的可更新值,然后是,您应该使用锁或其他同步方法进行读写;并且可能在使用该值的整个范围内阻塞。

答案 7 :(得分:2)

答案取决于它。如果线程访问变量时变量的值没有改变。否则,它需要。

此外,您可以使用Interlocked.XXX系列来保持读/写变量的原子性。

答案 8 :(得分:1)

必要吗?否。

...但是如果另一个线程可能在读取期间尝试写入它(如集合等),那么这可能是一个好主意。

答案 9 :(得分:1)

除非您100%确定在读取器线程运行时变量的值不会发生变化,否则100%是必需的。

答案 10 :(得分:0)

只要在其他线程执行期间没有更改,您就不需要锁定它。 如果改变,你应该使用它。

答案 11 :(得分:0)

如果变量从未被某人写过(至少在可访问时),则无需锁定它,因为没有错过更新的可能性。如果您不关心错过的更新(也就是说,如果您获得较旧的值则不会出现问题),情况也是如此。否则你应该使用某种同步

相关问题