不受保护的共享变量访问是否始终是数据竞争?

时间:2016-04-17 21:53:48

标签: c++ c multithreading c++11 c11

假设x是共享的线程间变量并且func总是返回0,那么下面的代码是否包含C11和C ++ 11的数据竞争?请假设x是用两个不同的线程写的,除了下面的switch语句外,总是有一个正确的锁。

int x; // global variable

...

int y; // local variable

...

switch (func())
{
  case 1:
  {
    x = 0;
    y = 1;
    break;
  }
  case 2:
  {
    x = 0;
    y = 2;
    break;
  }
  case 3:
  default:
  {
    y = 3;
    break;
  }
}

标准中有一个注释(C11和C ++ 11),它排除了编译器转换,从而引入了代码的数据竞争。是否允许编译器转换代码如下所示?下面的代码肯定包含一个数据竞争,但问题是编译器是否已经引入它或者它是否已经在原始代码中。虽然无法访问,但是对共享变量进行了不受保护的访问。

int x; // global variable

...

int y; // local variable

...

temp = x;
x = 0;
switch (func())
{
  case 1:
  {
    y = 1;
    break;
  }
  case 2:
  {
    y = 2;
    break;
  }
  case 3:
  default:
  {
    x = temp;
    y = 3;
    break;
  }
}

1 个答案:

答案 0 :(得分:4)

在C ++标准中,定义了一个种族:

  

1.10 / 4:如果其中一个修改内存位置而另一个访问或   修改相同的内存位置。

     

1.10 / 21:如果一个程序的执行在不同的线程中包含两个冲突的动作,则至少有一个   这不是原子的,也不会发生在另一个之前。任何这样的   数据竞争导致未定义的行为。

假设您有多个线程运行相同的代码,由于func()将始终返回0(您的声明),所以没有任何线程可以更改x的内容。此外,y是由线程执行的函数的局部变量,因此不共享。因此,在这种情况下不会发生竞争条件。

不允许编译器进行与第二个片段相对应的转换,因为:

  

1.10 / 22:编译器转换,它将分配引入可能不会被修改的共享内存位置   抽象机器通常被这个标准排除在外   赋值可能会覆盖另一个线程的另一个赋值   在抽象机器执行不具备的情况下   遇到了数据竞赛。

但是如果你自己编写片段,在上面解释的条件下可能会遇到竞争条件,因为x不是原子的,并且可能在一个线程(temp=x)中具有读访问权限而在另一个线程中具有写访问权(或者x=0或其他帖子的默认部分(x=temp