允许对C ++ 11中的循环进行编译器优化

时间:2013-03-03 15:55:35

标签: c++ language-lawyer

允许从C ++ 11兼容的编译器优化/转换此代码:

bool x = true; // *not* an atomic type, but suppose bool can be read/written atomically
/*...*/
{
    while (x); // spins until another thread changes the value of x
}

等同于无限循环的任何东西:

{
    while (true); // infinite loop
}

从单线程程序的角度来看,上述转换肯定是有效的,但这不是一般情况。

另外,在C ++ 11之前是否允许优化?

2 个答案:

答案 0 :(得分:13)

<强>绝对

由于x未标记为volatile,并且似乎是具有自动存储持续时间和内部链接的本地对象,并且程序未对其进行修改,因此这两个程序是等效的。

在C ++ 03和C ++ 11中,这是按照as-if规则,因为访问非易失性对象被认为是程序的“副作用” :

  

[C++11: 1.9/12]: 访问由volatile glvalue(3.10)指定的对象,修改对象,调用库I / O函数或调用执行任何这些操作的函数都是副作用,这是执行环境状态的变化。表达式(或子表达式)的评估通常包括   两个值计算(包括确定glvalue评估对象的身份并获取先前分配给对象以进行prvalue评估的值)和启动副作用。当对库I / O函数的调用返回或对volatile对象的访问进行评估时,即使调用隐含的某些外部操作(例如I / O本身)或易失性访问,也会认为副作用已完成可能尚未完成。

C ++ 11确实为全局对象腾出空间,使其在一个线程中更改其值,然后在另一个线程中读取新值:

  

[C++11: 1.10/3]:特定点上线程T可见的对象的值是对象的初始值,T指定给对象的值,或根据以下规则由另一个线程分配给该对象的值。

但是,如果你这样做,因为你的对象不是原子的:

  

[C++11: 1.10/21]:程序的执行包含数据竞争,如果它在不同的线程中包含两个冲突的动作,其中至少有一个不是原子的,并且都不会发生在另一个之前。任何此类数据竞争都会导致未定义的行为。

并且,当调用未定义的行为时,可能发生任何事情

Bootnote

  

[C++11: 1.10/25]:实现应该确保原子或同步操作分配的最后一个值(按修改顺序)在有限的时间内对所有其他线程可见。

再次注意,该对象必须是 atomic (例如,std::atomic<bool>)才能获得此保证。

答案 1 :(得分:1)

允许编译器对这两个循环做任何事情。包括终止程序。因为无限循环具有未定义的行为,如果它们不执行类似同步的操作(执行需要与另一个线程或I / O同步的事情),根据C++ memory model

  

请注意,这意味着具有无限递归或无限循环的程序(无论是作为for语句实现还是通过循环goto或其他方式)具有未定义的行为。

相关问题