为什么在以下情况下没有数据竞争?

时间:2017-02-11 18:39:51

标签: c++ c++11 concurrency

当两个线程同时访问同一个变量并且至少有一个访问是写入时,就会发生数据争用。

https://isocpp.org/wiki/faq/cpp11-language-concurrency

// start with x==0 and y==0
if (x) y = 1;   // Thread 1 
if (y) x = 1;   // Thread 2 
  

这里有问题吗?更确切地说,是否有数据竞争? (没有   没有)。

为什么原始文章声称这里没有数据竞争?

5 个答案:

答案 0 :(得分:14)

两个线程都不会写入,因为在条件之前这两个变量都不是非零。

答案 1 :(得分:11)

数据争用不是代码的静态属性。它们是执行时程序实际状态的属性。因此,虽然该程序可能处于代码会产生数据竞争的状态,但这不是问题。

问题是,鉴于系统的状态,代码会导致数据竞争吗?并且由于程序处于这样的状态,即两个线程都不会写入任何变量,因此代码不会导致数据竞争。

数据竞赛不是您的代码可能所做的事情。这是关于他们将要做什么。就像一个接受指针的函数不是未定义的行为,因为它使用指针而不检查NULL。如果有人传递一个真正为NULL的指针,那么它只是UB。

答案 2 :(得分:9)

因为xy都是零,所以C ++标准定义的抽象机器不能写入任何一个内存位置,所以这可能是一个问题的唯一方法就是实现决定了无论如何写入内存位置。例如,如果它转换了

if (x) y = 1;

y = 1;
if (!x) y = 0;

这是as-if规则下可能有效的重写,因为任何一个线程观察到的行为都是相同的(C ++ 14 1.9 [intro.execution])

  

本国际标准中的语义描述定义了参数化的非确定性摘要   机。本国际标准对符合实施的结构没有要求。   特别是,它们不需要复制或模拟抽象机器的结构。相反,符合   如下所述,实现需要模拟(仅)抽象机器的可观察行为   下方。

这实际上是在C ++ 11之前的有效重写,但是从C ++ 11开始,考虑了执行的线程。因此,只要抽象机器中不发生数据争用,就不允许实现跨线程进行不同观察行为的更改。

C ++ 14标准中有一个特别注释适用于此处(C ++ 14 1.10 [into.multithread]第22段)

  

[注意:编译器转换会将分配引入可能共享的内存位置   本标准通常排除抽象机器不会修改,因为这样   在抽象机器的情况下,赋值可能会覆盖另一个线程的另一个赋值   执行不会遇到数据竞争。   ...

因此,重写无效。实现必须保留xy未被修改的观察到的行为,即使是跨线程也是如此。因此,没有数据竞争。

答案 3 :(得分:2)

我发现这篇文章是Hans-J写的。 Boehm照亮:
http://www.hpl.hp.com/techreports/2009/HPL-2009-259html.html#races

  

我们说两个普通的内存操作在访问时会发生冲突   相同的内存位置(例如,变量或数组元素)和   至少有一个人写到该位置

     

我们说程序允许对特定输入集进行数据竞争   如果有一个顺序一致的执行,那就是了   交织各个线程的操作,其中两个   冲突操作可以“同时”执行。对于我们   目的,两个这样的操作可以“同时”执行,如果   它们在交错中彼此相邻,并且对应于   不同的线程。

文章接着我们的观点:

  

我们对数据竞争的定义相当严格:必须有   执行原始未转换程序的实际方式   冲突操作并行发生。这给你带来了负担   编制者不要通过引入有害数据竞赛来“打破”程序。

正如文章中所述,报告相同的例子(和其他人): 这个程序没有顺序一致的执行,其中线程1分配给y ,因为x和y永远不会变为非零。实际上你永远不会满足条件,所以没有人写入另一个线程可能正在阅读的变量。

要了解存在数据竞争的情况,请尝试考虑文章中的以下示例:

y = ((x != 0)? 1 : y)  # Thread 1
y = 2;                 # Thread 2

在最后一种情况下,很明显可能发生y由线程1分配(写入)而线程2执行y = 2;y由线程1写入,无论如何)。可能会发生数据竞争。

答案 4 :(得分:0)

如果未设置x,则不会将y设置为1,反之亦然。所以,这里的事情确实是按顺序发生的。