int变量的并发递增
Concurrent incrementing of a int variable
面试中的一个问题
int count = 0;
void func1()
{
for ( int i =0 ; i < 10; ++i )
count = count + 1;
}
void func2()
{
for ( int i =0 ; i < 10; ++i )
count++;
}
void func3()
{
for ( int i =0 ; i < 10; ++i )
++count;
}
int main()
{
thread(func1);
thread(func2);
thread(func3);
//joining all the threads
return 0;
}
问题是:理论上count
的取值范围是多少?上界显然是30,下界是多少?他们告诉我这是10
,但我不确定。否则,我们为什么需要内存屏障?
范围的下界是多少?
这是未定义的行为,所以count
可以取任何值可以想象。否则程序会崩溃
James Kanze的答案对于所有实际目的来说都是正确的,但是在这种特殊情况下,如果代码完全按照所写的并且这里使用的thread
是来自c++ 11的std::thread
,则行为实际上是定义的。
特别地,thread(func1);
将启动一个运行func1
的线程。然后,在表达式结束时,临时线程对象将被销毁,没有对其调用join或detach。因此线程仍然是可接合的,标准定义在这种情况下,析构函数调用std::terminate
。(参见[thread.thread.destr]: "If joinable() then terminate(),否则没有效果。")所以你的程序终止了。
因为这发生在第二个线程启动之前,所以没有实际的竞争条件——第一个线程是唯一一个接触count的线程,如果它甚至达到了那个程度。
从简单的部分开始,明显的上限是30,因为如果一切顺利,你有3个函数调用;每个都可以将count
增加10倍。总体:3 * 10 = 30。
对于下限,它们是正确的,这就是为什么-最坏的情况是每次一个线程试图增加count
时,其他线程将在完全相同的时间这样做。请记住,++count
实际上是以下伪代码:
count_temp = count;
count_temp = count_temp+1;
count = count_temp;
很明显,如果它们同时执行相同的代码,则只有10个实际增量,因为它们都读取相同的count
初始值,并且都写回相同的增加值。
首先,我要感谢你们给了我深入阅读标准的理由。否则我无法继续这场辩论。
标准在第1.10节第21条:The execution of a program contains a data race if it contains two conflicting actions in different threads, at least one of which is not atomic, and neither happens before the other. Any such data race results in undefined behavior.
然而,undefined behavior
这个术语也在标准1.3.24节:behavior for which this International Standard imposes no requirements... Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment...
考虑到Sebasian关于std::terminate
的回答,并假设这些线程不会抛出异常从而导致过早终止;虽然标准没有定义结果,但由于算法的简单性,结果可能是相当明显的。换句话说,虽然100%准确的答案是结果是不确定的,但我仍然认为可能结果的范围是明确的,由于characteristic of the environment
,它是10-30。
BTW -我真的想做一个评论,而不是另一个答案,但是它太长了
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 将数组的地址分配给变量并删除
- 为"adjacent"变量赋值时出现问题
- enum是C++中的宏变量还是整数变量
- 在全局变量中保存类的实例以重新创建类(创建"backup")
- 用C++中的一个变量定义一个常量
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 你能重载对象变量名本身返回的内容吗
- 内置函数可查看CPP中的成员变量
- 是否可以初始化不可复制类型的成员变量(或基类)
- 非原子变量上的并发读取
- 为并发运行时实现任务本地变量
- C++多线程使用并发变量停止线程
- openMP - 并发访问变量和原子
- 并发:用于多线程环境中共享变量的C++11内存模型
- 避免并发访问变量
- 并发修改和读取单个全局变量
- int变量的并发递增
- 可能并发写*相同*值到整数.我需要一个原子变量吗?