68

次の関数呼び出しがあるとします。

f(g(), h())

関数の引数の評価の順序は指定されていないので(私が知る限り、C ++ 11の場合もそうです)、実装は理論的に並列に実行できg()ますh()か?

このような並列化はg、並行性hの問題を引き起こさないようにするために、かなり些細なこと(最も明白なケースでは、自分の体にローカルなデータにのみアクセスする)でしか開始できませんでしたが、その制限を超えると、それを禁止するものは何も見えません。

それで、標準はそれを許可しますか?as-ifルールだけでも?

この回答では、Mankarseは別の方法で主張していますが、彼は標準を引用しておらず、私の読み過ごしでは[expr.call]明白な表現は明らかにされていません。)

4

4 に答える 4

42

要件は次の[intro.execution]/15とおりです。

...関数を呼び出す場合...呼び出された関数の本体の実行の前後に特に順序付けられていない呼び出し元の関数(他の関数呼び出しを含む)のすべての評価は、の実行に関して不確定に順序付けられます。呼び出された関数[脚注:言い換えると、関数の実行は相互にインターリーブしません。]。

したがって、の本体の実行は、 (呼び出し元の関数の式であるためg())の評価と不確定に順序付けられる(つまり、重複しない)必要があります。h()h()

ここで重要なのは、g()h()は両方とも関数呼び出しであるということです。

(もちろん、as-ifルールは、可能性を完全に排除することはできないことを意味しますが、プログラムの観察可能な動作に影響を与えるような方法で発生することはありません。せいぜい、そのような実装は、コード。)

于 2012-11-18T23:50:31.327 に答える
16

わからない限り、これらの関数を評価するためにコンパイラーが行うことは、完全にコンパイラー次第です。明らかに、関数の評価には、データの競合が発生するため、共有された可変データへのアクセスを含めることはできません。基本的な指針となる原則は、「あたかも」ルールと基本的な監視可能な操作、つまりvolatileデータへのアクセス、I / O操作、アトミックデータへのアクセスなどです。関連するセクションは1.9[intro.execution]です。

于 2012-11-18T19:25:45.427 に答える
3

コンパイラが、、、および彼らが呼び出すものが何をするg()のかを正確に知っていない限り、そうではありません。h()

2つの式は関数呼び出しであり、未知の副作用が発生する可能性があります。したがって、それらを並列化すると、これらの副作用でデータ競合が発生する可能性があります。C ++標準では、引数の評価で式の副作用でデータ競合が発生することは許可されていないため、コンパイラは、そのようなデータ競合が不可能であることがわかっている場合にのみ、式を並列化できます。

つまり、各関数をウォークスルーし、それらが実行および/または呼び出すものを正確に確認してから、それらの関数を追跡するなどです。一般的な場合、それは実行可能ではありません。

于 2012-11-18T19:24:45.813 に答える
1

簡単な答え:関数がシーケンスされている場合、不確定であっても、2つの間の競合状態の可能性はありません。これは、並列化されている場合は当てはまりません。1行の「些細な」関数のペアでさえそれを行うことができます。

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


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

がとpで共有される名前の場合、とを任意の順序で順番に呼び出すと、変更されないことでポイントされる値になります。それらが並列化されている場合、その読み取りと割り当ては、2つの間で任意にインターリーブできます。ghghp*p

  1. g値1を読み取っ*pて見つけます。
  2. f値1を読み取り*p、検索します。
  3. gに2を書き込みます*p
  4. f、前に読み取った値1を引き続き使用すると、0がに書き込まれ*pます。

したがって、並列化すると動作が異なります。

于 2012-11-21T06:23:43.470 に答える