14

面试中的一个问题

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

4 回答 4

16

这是未定义的行为,因此count可以具有任何可以想象的价值。否则程序可能会崩溃。

于 2013-05-07T10:35:12.020 回答
14

James Kanze 的答案对于所有实际目的都是正确的,但在这种特殊情况下,如果代码完全按照编写的方式编写并且thread此处使用的std::thread来自 C++11,则实际上定义了行为。

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

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

于 2013-05-07T10:46:25.913 回答
4

从简单的部分开始,明显的上限是 30,因为如果一切顺利,您将有 3 次函数调用;每个能够增加count10 倍。总体:3*10=30。

广告到下限,它们是正确的,这就是为什么 - 最坏的情况是每次一个线程尝试递增count时,其他线程将在完全相同的时间这样做。请记住,++count实际上是以下伪代码:

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

很明显,如果它们都同时执行相同的代码,那么您只有 10 个实际增量,因为它们都读取相同的初始值,count并且都写回相同的附加值。

于 2013-05-07T10:37:35.007 回答
2

首先,我要感谢你们让我有理由深入阅读该标准。否则我将无法继续这场辩论。

该标准在第 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% 准确的答案是结果未定义 - 我仍然认为可能结果的范围是明确定义的,并且是 10-30,因为characteristic of the environment.

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

于 2013-05-08T07:35:29.113 回答