并发递增int变量

时间:2013-05-07 10:32:32

标签: c++ concurrency

求职面试的问题

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,但我不确定。否则,为什么我们需要记忆障碍?

那么,范围的下限是什么?

4 个答案:

答案 0 :(得分:15)

这是未定义的行为,因此count可以采用任何值 可以想象的。或者程序可能崩溃。

答案 1 :(得分:13)

詹姆斯·坎泽的答案是出于所有实际目的的正确答案,但在这种特殊情况下,如果代码完全按照书面编写而且此处使用的thread是来自C ++ 11的std::thread,行为实际上是定义的。

特别是,thread(func1);将启动一个运行func1的线程。然后,在表达式的末尾,临时线程对象将被销毁,而不会在其上调用join或detach。所以线程仍然可以连接,标准定义在这种情况下,析构函数调用std::terminate。 (参见[thread.thread.destr]:“如果是joinable()则是terminate(),否则没有效果。”)所以你的程序会中止。

因为这是在第二个线程开始之前发生的,所以没有实际的竞争条件 - 第一个线程是唯一一个触及计数的线程,如果它甚至到达那么远。

答案 2 :(得分:4)

从简单部分开始,明显的上限是30,因为如果一切正常,你有3个函数调用;每个都能增加count 10次。总体而言:3 * 10 = 30。

Ad to the lower bound,它们是正确的,这就是为什么 - 最糟糕的情况是每次一个线程试图递增count时,其他线程将在同一时间这样做。请记住,++count实际上是以下伪代码:

count_temp = count;
count_temp = count_temp+1;
count = count_temp;

显而易见的是,如果它们同时执行相同的代码,则只有10个实数增量,因为它们都读取count的相同初始值,并且所有都写回相同的附加值。

答案 3 :(得分:2)

首先,我要感谢你们让我推理我深入阅读standard。否则,我无法继续这场辩论。

标准在第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。

顺便说一句 - 我真的想把它作为评论而不是另一个答案,但它太长了