++运算符线程安全吗?
注意:我并不是很擅长Multithreaded编程,但是我现在的项目让我这么做,所以我试图让我的脑海里围绕着什么是线程安全的,什么不是。
我正在阅读Eric Lippert 关于我所做的++的真棒答案之一 。 他说这就是真正发生的事情:
- 评估x来产生variables
- 该variables的值被复制到一个临时位置
- 临时值会递增以产生一个新值(不会覆盖临时!)
- 新值存储在variables中
- 操作的结果是新的价值
这让我想,如果两个线程调用++我怎么办? 如果第二个线程在步骤2时第一个线程在步骤3.(意思是如果第二个线程在第一个线程将新值存储在variables中之前将第二个线程拷贝到临时位置,该怎么办?
如果发生这种情况,那么似乎这两个线程只会增加i
一次,而不是两次。 (除非整个事情都在lock
)
正如其他答案指出,不,++不是“线程安全”。
我认为在你了解multithreading及其危害时,可以帮助你理解“线程安全”是什么意思,因为不同的人意味着不同的东西。 从本质上讲,线程安全的方面在于这个操作是否是primefaces操作。 当一个“primefaces”操作被另一个线程中断时,保证不会中途完成。
(还有很多其他线程问题与primefaces性无关,但也可能属于某些人对线程安全性的定义,例如,给定两个线程,每个线程对variables进行变异,两个线程分别读取variables,读者保证同意其他两个线程发生突变的顺序 ,如果你的逻辑依赖于这个线程,那么即使每个读写都是primefaces的,你也有一个非常难以处理的线程安全问题。
在C#中,几乎没有什么是保证是primefaces的。 简述:
- 读一个32位的整数或浮点数
- 阅读参考
- 写一个32位整数或浮点数
- 写一个参考
保证是primefaces的(具体细节见规范)
特别是,读取和写入64位整数或浮点数不保证是primefaces的。 如果你说:
Cx = 0xDEADBEEF00000000;
在一个线程,和
Cx = 0x000000000BADF00D;
在另一个线程上,那么有可能在第三个线程上:
Console.WriteLine(Cx);
有写出0xDEADBEEF0BADF00D,即使逻辑上variables永远不会保留该值。 C#语言保留写作的权利,等同于一个接一个地写两个整数,实践中一些芯片实际上是这样实现的。 第一次写入后的线程切换可能会导致读取器读取意外的内容。
它的长短是:不要在两个线程之间共享任何东西而不locking某些东西。 满足时锁只是缓慢的; 如果由于竞争锁造成性能问题,那么修复任何导致竞争锁的体系结构缺陷 。 如果这些锁没有争用,而且速度太慢,那么只有在这种情况下才能考虑采用危险的低锁技术。
这里使用的常见的低锁技术当然是调用Threading.Interlocked.Increment
,它以保证为primefaces的方式增加一个整数。 (请注意,如果两个线程在不同的时间每次执行两个不同的variables的互锁增量,而其他线程正试图确定哪个增量“首先”发生,那么它仍然不能保证会发生什么情况。所有线程都可以看到一个一致的事件顺序。)
不,不是的。
你提出的分析是非常正确的 – ++
(和--
)运算符如果没有使用适当的locking语义,就容易受到竞争条件的影响。
这些都很难得到正确的结果,但幸好BCL已经为这些特殊情况提供了一个现成的解决scheme:
如果你想要一个primefaces增量操作,你应该使用Interlocked.Increment
。 Interlocked
类还定义了一个Decrement
和其他一些有用的primefaces操作。
递增指定的variables并将结果存储为primefaces操作。
不, i++
看起来很紧凑,但它确实是i = i + 1
简写forms,并且在这种forms中,更容易看到它涉及“i”的读取和写入。 没有locking它根本不是线程安全的。
另外两个参数是:
- `++'没有被定义为线程安全的
-
Interlocked.Increment (ref int x)
的存在
线程安全是罕见的和昂贵的,它将被清楚地广告时可用。