通过两个线程递增的全局变量的最终值

时间:2017-12-27 08:44:34

标签: c++ c multithreading race-condition

我遇到了这个问题:

  

给定两个线程和一个全局变量var,两个线程运行   相同的代码(C / C ++代码):

for(int i=0; i<20; i++)
{
  var++;
}
     

线程末尾的var有哪些可能的值   执行?

如果每个线程“正确”增加var - 我猜最大值将为40.

但最低价值呢?如何实现增量操作并实际完成?

注意:对于增量操作没有任何锁定(任何类型)(当然,正确的方法是锁定它 - 问题是出于教育目的)。

2 个答案:

答案 0 :(得分:7)

如果var 不是原子类型,则行为未定义。因此,关于可能的最终值的范围的问题是不适当的。

如果var是原子类型,那么最终结果就好像线程没有同时运行一样。

答案 1 :(得分:3)

如果你没有做任何锁定,那么var++不是原子的,即变量的写入和读取可以被另一个线程中断。这意味着两个线程都可以读取相同的var值,并同时增加它。

最坏的情况是两个线程完全&#34;同步&#34;那是在完全相同的时间读取和写入var,因此var的最小结束值为20。

更新:显然,这些数据竞赛无法保证可能的结果,请参阅下面的Bathsheba答案以及他提到的this article

更新2 :我很好奇,如果在现实世界中我们会看到低于20的值。测试设置(详情:请参阅this gist

  • 全球int var。使用longlong long进行测试,没有任何区别
  • 两个pthread做了20 {000}次var++
  • 可执行文件已启动10&000,000次,并且已采用最小值

预期结果将在20到000和40&000; 000之间:

|                    Computer                   | clang | clang -O3 |  gcc  | gcc -O0 | gcc -O2 |
|-----------------------------------------------|-------|-----------|-------|---------|---------|
| Linux, ThinkPad, x86_64, Intel I7, 4 cores    | 19402 |     20000 | 18760 |   16913 |   20000 |
| Linux, Raspberry 3, ARMv7, 4 cores            | 19587 |     20000 | 19569 |   19904 |   20000 |
| OSX,  Intel i5, 4 cores                       | 17609 |     20000 | 17206 |   18049 |   20000 |
| Linux, EC2 t2.2xlarge, Intel Xeon E5, 8 cores | 19707 |     20000 | 19744 |   19881 |   40000 |

看起来很有趣:

  • 是的,它可以降到20以下,所以&#34;没有保证&#34;索赔不只是理论上的
  • 编译器优化超过一定级别,行为看起来更可预测
  • 奇怪,在具有8个核心的EC2上,gcc -O2的最小值为40&#39;