Could a C++ implementation, in theory, parallelise the evaluation of two function arguments?

C++Language Lawyer

C++ Problem Overview


Given the following function call:

f(g(), h())

since the order of evaluation of function arguments is unspecified (still the case in C++11 as far as I'm aware), could an implementation theoretically execute g() and h() in parallel?

Such a parallelisation could only kick in were g and h known to be fairly trivial (in the most obvious case, accessing only data local to their bodies) so as not to introduce concurrency issues but, beyond that restriction I can't see anything to prohibit it.

So, does the standard allow it? Even if only by the as-if rule?

(In this answer, Mankarse asserts otherwise; however, he does not cite the standard, and my read-through of [expr.call] hasn't revealed any obvious wording.)

C++ Solutions


Solution 1 - C++

The requirement comes from [intro.execution]/15:

>... When calling a function ... Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function [Footnote: In other words, function executions do not interleave with each other.].

So any execution of the body of g() must be indeterminately sequenced with (that is, not overlapping with) the evaluation of h() (because h() is an expression in the calling function).

The critical point here is that g() and h() are both function calls.

(Of course, the as-if rule means that the possibility cannot be entirely ruled out, but it should never happen in a way that could affect the observable behaviour of a program. At most, such an implementation would just change the performance characteristics of the code.)

Solution 2 - C++

As long as you can't tell, whatever the compiler does to evaluate these functions is entirely up to the compiler. Clearly, the evaluation of the functions cannot involve any access to shared, mutable data as this would introduce data races. The basic guiding principle is the "as if"-rule and the fundamental observable operations, i.e., access to volatile data, I/O operations, access to atomic data, etc. The relevant section is 1.9 [intro.execution].

Solution 3 - C++

Not unless the compiler knew exactly what g(), h(), and anything they call does.

The two expressions are function calls, which may have unknown side effects. Therefore, parallelizing them could cause a data-race on those side effects. Since the C++ standard does not allow argument evaluation to cause a data-race on any side effects of the expressions, the compiler can only parallelize them if it knows that no such data race is possible.

That means walking though each function and look at exactly what they do and/or call, then tracking through those functions, etc. In the general case, it's not feasible.

Solution 4 - C++

Easy answer: when the functions are sequenced, even if indeterminately, there is no possibility for a race condition between the two, which is not true if they are parallelized. Even a pair of one line "trivial" functions could do it.

void g()
{
    *p = *p + 1;
}


void h()
{
    *p = *p - 1;
}

If p is a name shared by g and h, then a sequential calling of g and h in any order will result in the value pointed to by p not changing. If they are parallelized, the reading of *p and the assigning of it could be interleaved arbitrarily between the two:

  1. g reads *p and finds the value 1.
  2. f reads *p and also finds the value 1.
  3. g writes 2 to *p.
  4. f, still using the value 1 it read before will write 0 to *p.

Thus, the behavior is different when they are parallelized.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLightness Races in OrbitView Question on Stackoverflow
Solution 1 - C++MankarseView Answer on Stackoverflow
Solution 2 - C++Dietmar KühlView Answer on Stackoverflow
Solution 3 - C++Nicol BolasView Answer on Stackoverflow
Solution 4 - C++nevsanView Answer on Stackoverflow