例如,bool
多线程时是否需要锁定一个值?
4 回答
没有原子类型这样的东西。只有操作可以是原子的。
读取和写入适合单个字的数据类型(int
在 32 位处理器上,long
在 64 位处理器上)在技术上是“原子的”,但抖动和/或处理器可以决定重新排序指令并因此产生意想不到的竞争条件,因此您需要使用 序列化访问lock
,使用Interlocked
类进行写入(在某些情况下读取),或声明变量volatile
.
简短的回答是:如果两个不同的线程可以访问同一个字段/变量,并且其中至少有一个正在写入,那么您需要使用某种锁定。对于通常是Interlocked
类的原始类型。
有点。这里有一个很好的主题,但简短的版本是,虽然给定的读取或写入可能是原子的,但几乎从来不是你在做什么。例如,如果要增加一个整数,则需要 1) 读取值,2) 将值加 1,3) 将值存储回来。这些操作中的任何一个都可以被中断。
这就是诸如“互锁”之类的课程的原因。
类似的问题在这里
对于明确的答案去规范。:)
CLI 规范的第 I 部分第 12.6.6 节指出:“当对一个位置的所有写访问大小相同时,符合标准的 CLI 应保证对不大于本机字大小的正确对齐的内存位置的读写访问是原子的。”
这证实了 s_Initialized 永远不会不稳定,并且对原始类型的读写是原子的。
互锁创建了一个内存屏障,以防止处理器重新排序读取和写入。在这个例子中,锁创建了唯一需要的屏障。
约翰。
本质上,您不会因为不锁定布尔值而出现“崩溃”问题。您可能拥有的是更新或读取布尔值的顺序的竞争条件。如果您想保证 bool 是以特定顺序写入/读取的,那么您需要使用某种锁定机制。
静态原始类型是线程安全的,因此您不需要锁定那些类型化的变量。但是,不能保证原始类型的任何实例变量都是如此。见这里:像 bool 线程安全的原始类型吗?
这是另一个可能也很有趣的有用链接,我发现该解决方案非常引人注目:所以问题:我如何知道 C# 方法是否是线程安全的?