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

wlwcrazw  于 2023-05-02  发布在  其他
关注(0)|答案(2)|浏览(148)

假设我们有下面的代码

int test(bool* flag, int* y)
{
    if(*y)
    {
        *flag = false;
    else
    {
        *flag = true;
    }
}

注意,编译器可以在这里证明write to flag总是会发生,所以我认为下面的一个是允许的(我不认为它是优化的,但只是为了示例)

int test(bool* flag, int* y)
{
    *flag = true;
    if(*y)
    {
        *flag = false;
    }
}

所以现在,我们也将true写入flag if y!=0,但是从as-if规则来看,这看起来是有效的。
但我仍然认为,这种优化是奇怪的,假设*y = true总是,所以标志总是假的,所以如果其他一些线程读取标志变量,他可能会看到真的,虽然它不应该发生,所以它打破了as-if规则?优化是否有效?
补充:非原子的情况是清楚的,因为它的UB,所有的赌注都是关闭的,但如果标志是原子的,放松排序,然后呢?

3pmvbmvn

3pmvbmvn1#

转换是有效的(仅基于标准定义的内容,即:即假设严格的混叠)。
任何其他线程都不可能观察到中间值,因为当函数在另一个线程上执行时,不允许任何线程读取*flag
*flag不是一个原子对象,该函数总是写入*flag,而另一个线程阅读它时不同步,因此会导致未定义的行为,因为它是一个数据竞争,而不管采取的路径如何。
如果flag的类型是(std::)atomic_bool*,那么,不管使用什么内存顺序,转换通常都是无效的,因为,正如你所说的,另一个线程可能会观察到一个它本不应该观察到的值。

ivqmmu1c

ivqmmu1c2#

给出:

int test(bool* flag, int* y) {
  if(*y)

以下(与OP的代码略有不同)是不允许的

// int test(bool* flag, int* y) {
int test(bool* flag, bool* y) {
// or 
int test(int* flag, int* y) {
  *flag = true;

...因为指向同一类型数据的指针可能指向同一条数据:即指针相同。那么代码更改在功能上就不一样了。
如果代码为:

int test(same_type* restrict flag, same_type* restrict y) {

然后编译器可以假设指针不指向重叠的数据,即使它们指向相同的类型。

相关问题