0

我想了解编译器对 C 中的非易失性变量有什么限制。

我不确定它是否真实,但有人告诉我,如果你有以下代码:

int x;
...
void update_x() {
  lock();
  x = x*5+3;
  unlock();
} 

您必须获取锁才能读取 x,因为即使很难编译器也不太可能这样做,从技术上讲,它将诸如 x*5 之类的中间计算存储到 x 中是合法的,因此读取可能会读取中间值。所以我的第一个问题是是否确实如此?如果不是,为什么不呢?

如果是,我有一个后续问题,是否有任何东西阻止编译器在获取锁之前或之后使用 x 作为临时存储?(假设编译器可以证明执行程序的单个线程不会注意到它)。

如果不是,这是否意味着任何具有非易失性共享变量的程序在技术上都是未定义的,即使所有访问都受到锁的保护?

谢谢,伊利亚

4

1 回答 1

1

在 C11 之前,答案是否定的,因为规范没有定义多线程做什么,所以任何使用多线程的程序,其中一个线程写入一个对象,另一个线程读取它是未定义的行为。

对于 C11,实际上有一个内存模型讨论多线程和数据竞争,所以答案是肯定的,只要锁定/解锁例程执行某些同步操作(涉及执行同步的库函数或对特殊_Atomic对象的操作) .

由于 C11 规范试图对现有实现的行为进行编码(在大多数情况下),因此任何满足其要求的代码(即,使用实现提供的库进行锁定,或实现提供的原子操作扩展)都可能即使在 C11 之前的实现上也能正常工作。

C11 规范的第 5.2.1.4 节涵盖了这一点。

于 2013-05-28T17:32:34.123 回答