我想了解编译器对C中的非易失性变量有什么限制。
我不确定它的真实与否,但我被告知如果您有以下代码:
int x;
...
void update_x() {
lock();
x = x*5+3;
unlock();
}
你必须获得锁读取x,因为即使编译器不太可能这样做,在技术上合法的是将x * 5等中间计算存储到x中,因此读取可能会读取中间值。所以我的第一个问题是它是否确实如此?如果没有,为什么不呢?
如果是,我有一个后续问题,是否有什么阻止编译器在获取锁之前或之后使用x作为临时存储? (假设编译器可以证明执行程序的单个线程不会注意到它)。
如果没有,这是否意味着即使所有访问都受到锁保护,任何具有非易失性共享变量的程序在技术上都是未定义的?
谢谢, 伊利亚安德
答案 0 :(得分:1)
在C11之前,答案是否定,因为规范没有定义任何关于多个线程做什么的事情,所以任何使用多个线程的程序,其中一个线程写入一个对象而另一个线程读取它是未定义的行为。
对于C11,实际上有一个内存模型可以讨论多个线程和数据争用,所以答案是肯定的,只要锁定/解锁例程执行某些同步操作(涉及执行同步或操作的库函数)特殊_Atomic
个对象)。
由于C11规范试图编写现有实现的行为(大多数情况下),很可能是任何代码执行它所需要的(即,使用实现提供的库进行锁定,或实现提供的原子扩展)操作)即使在C11之前的实现上也能正常工作。
C11规范的第5.2.1.4节涵盖了这一点。