编译器是否允许在条件之前重新排序存储?

Mos*_*evy 0 c c++ x86 memory-model

假设我们有以下代码

int test(bool* flag, int* y)
{
    if(*y)
    {
        *flag = false;
    else
    {
        *flag = true;
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,编译器可以在这里证明写入标志总是会发生,所以我认为以下一个是允许的(我认为这根本不是优化,但只是为了示例)

int test(bool* flag, int* y)
{
    *flag = true;
    if(*y)
    {
        *flag = false;
    }
}
Run Code Online (Sandbox Code Playgroud)

所以现在,我们也将 true 写入 flag if y!=0,但从 as-if 规则的角度来看,这看起来是有效的。

但我仍然认为,这种优化很奇怪,假设*y = true总是这样,所以标志总是假的,所以如果其他线程读取标志变量,他可能会看到 true,尽管它永远不应该发生,所以它会破坏 as-如果统治?优化是否有效?

另外:非原子的情况很清楚,因为它是 UB,并且所有的赌注都取消了,但是如果标志是具有宽松排序的原子的,那么怎么办?

use*_*522 9

该转换是有效的(仅基于标准定义的内容,即假设严格别名)。

任何其他线程都不可能观察到中间值,因为*flag当该函数在另一个线程上执行时,任何线程都不允许读取。

*flag不是原子对象,该函数总是写入*flag,而另一个线程不同步地读取它,因此会导致未定义的行为,因为无论采用何种路径,它都是数据竞争。


如果flag有类型(std::)atomic_bool*,那么,无论使用什么内存顺序,转换通常都无效,因为,正如您所说,另一个线程有可能观察到它不应该观察到的值。