【问题标题】:C11 - omitting potentially infinite loop by the compilerC11 - 编译器忽略潜在的无限循环
【发布时间】:2022-01-07 22:32:09
【问题描述】:

假设以下代码

struct a {
    unsigned cntr;
};

void boo(struct a *v) {
    v->cntr++;
    while(v->cntr > 1);
}

由于C11标准中的以下语句,我想知道是否允许编译器省略boo()内的while循环:

控制表达式不是常量表达式的迭代语句,156) 不执行输入/输出操作,不访问 volatile 对象,并且在其主体中不执行同步或原子操作,控制表达式,或者(在 for 语句的情况下)它的表达式 3,可以被实现假定为终止。157)


157)这旨在允许编译器转换,例如即使在无法证明终止时也可以删除空循环。

v->cntr 在控制表达式中是否可以被视为一个同步,因为v 可能是指向可以在外部修改的全局结构的指针(例如由另一个线程)?

附加问题。 如果v 未定义为volatile,是否允许编译器在每次迭代时不重新读取v->cntr

【问题讨论】:

  • be considered as a synchronization since v may be a pointer to a global structure which can be modified externally 这是一个标准,它都是定义的,同步操作是定义的——像在你的代码中修改一个全局变量不是同步操作。
  • @KamilCuk 在一个或多个内存位置上的同步操作是获取操作、释放操作、获取和释放操作或消耗操作。 - I找不到consume operation的定义,但是为什么不能将读取全局内存视为consume operation
  • 编译器可以为所欲为,只要可观察到的结果与在抽象 C 机器上执行的程序相同。
  • couldn't find the definition of consume operation For memory_order_consume, a load operation performs a consume operation port70.net/~nsz/c/c11/n1570.html#7.17.3p5
  • @tstanisl 这在这种情况下正好相反,因为我希望一旦v->cntr 达到大于 1 的值,流就会停止/挂起。在此处描述的情况下,流将永远不会停止,因为编译器可能会丢弃整个 while 循环

标签: c language-lawyer infinite-loop c11


【解决方案1】:

控制表达式中的v->cntr是否可以被视为同步

没有。

来自https://port70.net/~nsz/c/c11/n1570.html#5.1.2.4p5

该库定义了许多原子操作 (7.17) 和互斥锁操作 (7.26.4),它们被特别标识​​为同步操作。

所以基本上,来自stdatomic.hmtx_* 的函数来自thread.h 是同步操作。

因为 v 可能是指向全局结构的指针,可以在外部修改(例如由另一个线程)?

没关系。对我来说,假设听起来像是不允许许多合理的优化,我不希望我的编译器假设。

如果 v 在另一个线程中被修改,那么它将是未排序的,这只会导致未定义的行为 https://port70.net/~nsz/c/c11/n1570.html#5.1.2.4p25

如果 v 未定义为 volatile,是否允许编译器在每次迭代时不重新读取 v->cntr?

是的。

【讨论】:

  • 其他同步操作大部分是对原子对象的操作。因此,如果成员 cntr 是原子成员,boo 将永远等待,直到另一个线程确保条件。
猜你喜欢
  • 2011-07-14
  • 2017-10-07
  • 2017-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-08
  • 1970-01-01
相关资源
最近更新 更多