Re: About as-if rule and "observable behaviors"
{ quoted signature and server banner removed by mod. also edited
to wrap long lines to ~70 chars. please do that yourself next
time. thanks. -mod }
On Thursday, August 14, 2014 11:50:02 PM UTC+8, Joshua Cranmer ???? wrote:
On 8/14/2014 8:42 AM, Eric Z wrote:
{ reformatted by mod to wrap lines at ~70 chars. -mod }
Hi all,
What puzzles me recently is about the as-if rule in C++11.
The "as-if" rule basically defines what transformations an
implementation is allowed to perform on a legal C++ program. In
short, all transformations that do not affect a program's observable
behavior are allowed.
Let's say if a compiler is evaluating whether it can reorder two
instructions (e.g., a memory store) or not. If such a reorder doesn't
introduce any change in program's "observable behavior" (e.g., the
output order to a file or stdout), it's a valid optimization.
However, in a large program, how does a compiler know if such a
reordering will (or not) change a future observable behavior that may
come very late in program order?
I think you misunderstand how compilers apply the rule. Most of the
time, compilers operate on a basis of optimizing a region of code. The
optimizations that they can do on that region have to be equivalent for
all configurations of the program at the start of that region. One
consequence is that unknown code has to be treated conservatively.
The other question pertains to multi-threading in C++11. Does "as-if"
rule also apply to other threads in the abstract machine, or it only
applies to a single thread, as defined by pre-C++11 standards. i.e.,
Is it ok if this reordering changes some observable behaviors of
another thread?
There is another key aspect to optimization: undefined behavior.
Compilers do not have to preserve the semantics of programs that exhibit
undefined behavior. When multiple threads are involved, interactions of
threads outside of a few synchronization methods (e.g., std::mutex or
std::atomic) are classified of undefined behavior. This allows
multithreaded programs to be legally optimized on a more local basis.
There are two questions related.
1. Data race is where two or more threads have conflicting access
to a shared variable. And the standard says that using std::atomic
type (or other synchronization primitives) would solve the data race.
I wonder if bool variables are intrisically immune to any data race.
AFAIK, the load and the store to a bool type variable is
atomic/indivisble on all platforms. And a bool variable has its own
memory location guaranteed by the language.
So is it possible that a bool variable has any data race?
E.g.,
// global shared
bool value = false;
bool flag = false;
// thread 1
value = 6;
flag = true;
// thread 2
if (flag)
cout << value;
Is this code data race free? If there is no data race, there isn't
any undefined behavior. As a result, as-if rule should be respected.
And a compiler should not reorder the stores to "value" and "flag"
in thread 1 because that may lead to a change of observable behavior
in other threads like thread 2. Is that right?
2. If there is still any data race in 1, we can solve it by making
both variables atomic:
// global shared
atomic<bool> value = false;
atomic<bool> flag = false;
// thread 1
value.store(6, memory_order_relaxed); // (1)
flag(true, memory_order_relaxed); // (2)
// thread 2
if (flag.load(memory_order_relaxed))
cout << value.load(memory_order_relaxed);
This time it should be guaranteed that there is no data race in
this code. But we know that a compiler is still free to reorder
(1) and (2). Why can it do that?
The as-if rule applies here and the reorder may change some
observable behaviors of other threads (like thread 2). When
undefined behavior is not a problem, how can a compiler still
reorder these instructions? Doesn't it break the "as-if" rule?
Thanks!
Best regards,
Eric
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]