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

问题描述 投票:2回答:2

我遇到了这个问题:

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

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

在线程执行结束时var的可能值是什么?

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

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

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

c++ c multithreading race-condition
2个回答
7
投票

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

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


3
投票

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

最坏的情况是两个线程完全“同步”,即在完全相同的时间读取和写入var,因此var的最小结束值将为20。

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

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

  • 全球int var。用longlong long测试,没有任何区别
  • 两个pthreads做20'000倍var++
  • 可执行文件启动了10'000次并获得了最小值

预期结果将在20,000到40'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'000以下,所以“不保证”声称不仅仅是理论上的
  • 如果编译器优化超过一定级别,则行为看起来更具可预测性
  • 奇怪的是,在具有8个核心的EC2上,gcc -O2的最小值为40'000。
© www.soinside.com 2019 - 2024. All rights reserved.