++运算符线程安全吗?

注意:我并不是很擅长Multithreaded编程,但是我现在的项目让我这么做,所以我试图让我的脑海里围绕着什么是线程安全的,什么不是。

我正在阅读Eric Lippert 关于我所做的++的真棒答案之一 。 他说这就是真正发生的事情:

  1. 评估x来产生variables
  2. 该variables的值被复制到一个临时位置
  3. 临时值会递增以产生一个新值(不会覆盖临时!)
  4. 新值存储在variables中
  5. 操作的结果是新的价值

这让我想,如果两个线程调用++我怎么办? 如果第二个线程在步骤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.IncrementInterlocked类还定义了一个Decrement和其他一些有用的primefaces操作。

递增指定的variables并将结果存储为primefaces操作。

不, i++看起来很紧凑,但它确实是i = i + 1简写forms,并且在这种forms中,更容易看到它涉及“i”的读取和写入。 没有locking它根本不是线程安全的。

另外两个参数是:

  • `++'没有被定义为线程安全的
  • Interlocked.Increment (ref int x)的存在

线程安全是罕见的和昂贵的,它将被清楚地广告时可用。