Allowed compiler optimizations on loops in C++11

怎甘沉沦 提交于 2019-12-22 04:30:38

问题


Is a C++11-compliant compiler allowed to optimize/transform this code from:

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
}

to anything equivalent to an infinite loop:

{
    while (true); // infinite loop
}

The above conversion is certainly valid from the point of view of a single-thread program, but this is not the general case.

Also, was that optimization allowed in pre-C++11?


回答1:


Absolutely.

Since x is not marked as volatile and appears to be a local object with automatic storage duration and internal linkage, and the program does not modify it, the two programs are equivalent.

In both C++03 and C++11 this is by the as-if rule, since accessing a non-volatile object is not considered to be a "side effect" of the program:

[C++11: 1.9/12]: Accessing an object designated by a volatile glvalue (3.10), modifying an object, calling a library I/O function, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. Evaluation of an expression (or a sub-expression) in general includes both value computations (including determining the identity of an object for glvalue evaluation and fetching a value previously assigned to an object for prvalue evaluation) and initiation of side effects. When a call to a library I/O function returns or an access to a volatile object is evaluated the side effect is considered complete, even though some external actions implied by the call (such as the I/O itself) or by the volatile access may not have completed yet.

C++11 does make room for a global object to have its value changed in one thread then that new value read in another:

[C++11: 1.10/3]: The value of an object visible to a thread T at a particular point is the initial value of the object, a value assigned to the object by T, or a value assigned to the object by another thread, according to the rules below.

However, if you're doing this, since your object is not atomic:

[C++11: 1.10/21]: The execution of a program contains a data race if it contains two conflicting actions in different threads, at least one of which is not atomic, and neither happens before the other. Any such data race results in undefined behavior.

And, when undefined behaviour is invoked, anything can happen.

Bootnote

[C++11: 1.10/25]: An implementation should ensure that the last value (in modification order) assigned by an atomic or synchronization operation will become visible to all other threads in a finite period of time.

Again, note that the object would have to be atomic (say, std::atomic<bool>) to obtain this guarantee.




回答2:


The compiler is allowed go do anything to those two loops. Including terminating the program. Because infinite loops have undefined behaviour if they do not perform a synchronization-like operation (do something that requires synchronization with another thread or I/O), according to the C++ memory model:

Note that it means that a program with endless recursion or endless loop (whether implemented as a for-statement or by looping goto or otherwise) has undefined behavior.



来源:https://stackoverflow.com/questions/15187459/allowed-compiler-optimizations-on-loops-in-c11

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!