对共享变量的无保护访问是否总是数据竞赛



假设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;
  }
}

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

1.10/4:如果两个表达式求值中的一个修改内存位置,而另一个访问或修改相同的内存位置。

1.10/21:如果程序在不同线程中包含两个冲突操作,则程序的执行包含数据竞赛这不是原子性的,两者都没有发生在另一个之前。任何此类数据竞争会导致未定义的行为。

假设有几个线程运行相同的代码,由于func()总是返回0(您的声明),没有一个线程可以更改x的内容。此外,y是线程执行的函数的局部变量,因此它是不共享的。因此,在这种情况下不可能出现竞争情况。

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

1.10/22:编译器转换,将赋值引入一个潜在的共享内存位置,该位置不会被抽象机器通常被本标准排除在外,因为一个赋值可能会覆盖其他线程的另一个赋值在抽象机器执行不会遇到数据竞争。

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

最新更新