此示例是否包含数据争用?

时间:2018-01-05 07:45:33

标签: c multithreading c++11 java-memory-model memory-model

这是原始问题,但是我的问题有些不同。 C++ memory model - does this example contain a data race?

我的问题:

//CODE-1: initially, x == 0 and y == 0
if (x) y++; // pthread 1
if (y) x++; // pthread 2

注意:上面的代码是用C语言编写的,而不是用C ++编写的(没有内存模型)。那么它是否包含数据竞争?

从我的观点来看:如果我们在顺序一致性内存模型中查看代码,则没有数据竞争,因为x和y将永远不会同时为非零。但是,我们永远不能假设顺序一致性内存模型,因此编译器重新排序可以进行相对于内部线程正确性的转换,因为编译器不知道线程的存在....... ?

所以代码可以转换为:

//CODE-2
y++; if (!x) y--;
x++; if (!y) x--;

上述转换并没有违反顺序正确性,所以它是正确的。这不是编译器的错,对吗?所以我同意CODE-1包含数据竞争的观点。你呢?

我有一个额外的问题,带有内存模型的C ++ 11可以解决这个数据竞争,因为编译器知道线程,所以他们会根据内存模型类型进行重新排序,对吗?

2 个答案:

答案 0 :(得分:2)

C ++标准将数据争用(触发未定义的行为)定义为:

  

§1.10.1-2[intro.races]
  如果其中一个修改内存位置(..)而另一个读取或修改相同的内存位置,则两个表达式评估会发生冲突。

根据C ++内存模型规则,您的第一个代码片段不包含数据争用,因为C ++标准禁止编译器转换会引入这样的竞争:

  

§1.10.1-21[intro.races]
  引入可能由抽象机器修改的潜在共享内存位置的编译器的编译器转换通常被本国际标准排除,因为在抽象机器执行不执行的情况下,这样的分配可能会覆盖另一个线程的另一个分配。遇到了数据竞赛。

所以它说如果if语句中的条件(x)产生错误,则不允许修改y的转换,即使最终结果是y似乎没有修改。

第二个示例显然包含数据竞争,因为2个线程可以同时写入和读取x(同样适用于y)。

请注意,自版本11起,C ++和C都有内存模型。如果使用不支持C11的编译器,则不会正式定义多线程行为。

这是一个question,它显示了非法编译器转换的一个例子。

答案 1 :(得分:0)

  

// CODE-1:最初,x == 0和y == 0
     if(x)y ++; // pthread 1
     if(y)x ++; // pthread 2

没有未定义的行为,因为x和y都不会改变它们的值 但是,仍然存在竞争条件,因为在一个线程中的读访问与另一个线程中的写访问之间没有定义的序列。

  

// CODE-2
     ÿ++; if(!x)y--; // pthread 1
     X ++; if(!y)x--; // pthread 2

现在您有数据争用和未定义的行为,因为在线程1中的y++和线程2中的if(!y)之间没有序列,反之亦然。所以y的可能结果是:

  • y = 0
    线程1在线程2之后运行。因此x仍为0。
  • y = 1
    线程1与线程2并行运行,看到对x的更改,但反之则不然。所以y不会减少。

这与内存模型无关。在任何不同步的环境中,它只是一场竞赛。