5

2 つの配列があるとします。

int[] array1 = new int[2000000];
int[] array2 = new int[2000000];

いくつかの値を配列に貼り付けてから、次のように array2 の内容を array1 に追加します。

for(int i = 0; i < 2000000; ++i) array1[i] += array2[i];

ここで、マルチプロセッサ マシンで処理を高速化したい場合、上記のようなループを実行する代わりに、2 つのスレッドを作成します。1 つは配列の最初の 1000000 要素を処理し、もう 1 つは配列の最後の 1000000 要素を処理しました。私のメイン スレッドは、これら 2 つのスレッドが終了したことを通知するのを待ってから、すべての種類の重要なものに array1 の値を使用し始めます。(2 つのワーカー スレッドは終了せずに再利用できることに注意してください。ただし、メイン スレッドは、両方がそうするように通知するまで再開されません。)

そこで、私の質問は次のとおりです。2 つのワーカー スレッドが配列に対して行った変更をメイン スレッドが確実に確認できるようにするにはどうすればよいでしょうか。これが起こると期待できますか、それとも、ワーカー スレッドが書き込みを配列にフラッシュし、メイン スレッドがキャッシュされた配列値を破棄するように、特別な手順を実行する必要がありますか?

4

6 に答える 6

6

運が良く、.NET 4.0 を使用するオプションがある場合は、次のように記述できます。

Parallel.For(0, 2000000, i => { array1[i] += array2[i]; });

次の理由により、明示的なロックや同期は必要ありません。

  • 各タスク (forループ本体の実行) は、配列のばらばらの部分に影響を与えます
  • Parallel.For戻る前にすべてのタスクが終了するまで待機するため、暗黙的なメモリバリアが存在します。
于 2010-02-19T03:32:20.070 に答える
2

ワーカー スレッドの配列への書き込みが、期待どおりの順序でメイン スレッドに表示されるようにするには、メモリ バリアが必要です。

明示的なメモリ バリアが必要かどうかは、メイン スレッドへの通知方法によって異なります。イベントなどのほとんどの同期プリミティブを待機すると、暗黙的なバリアが提供されるため、変更は必要ありません。グローバル変数をポーリングしても、障壁はありません。

明示的なバリアが必要な場合は、Thread.MemoryBarrie r を使用してください。

于 2010-02-19T01:06:44.510 に答える
2

2 つのワーカー スレッドが配列に対して行った変更をメイン スレッドが確実に認識できるようにするにはどうすればよいでしょうか? これが起こると期待できますか、それとも、ワーカー スレッドが書き込みを配列にフラッシュし、メイン スレッドがキャッシュされた配列値を破棄するように、特別な手順を実行する必要がありますか?

ここでは特別な処理は必要ありません。常にメモリ内の同じオブジェクトを処理します。

また、各スレッドは配列の個別の部分で動作するため、ロックは必要ありません。

ただし、単純な追加のみを行っている場合は、スレッド化とメイン スレッドへの同期のオーバーヘッドが得られるメリットを上回る可能性があります。これを行う場合は、プロファイルを作成して、純利益が得られることを確認してください。

于 2010-02-19T01:07:14.647 に答える
2

提案したようにインデックス範囲を重複しない範囲に分割する場合、配列が共有メモリに作成されている場合 (つまり、各スレッドではなく)、ロックは必要ありません。

于 2010-02-19T01:07:47.660 に答える
0

配列の変更が完了したときにコールバックを使用している場合はおそらく問題ありませんが、疑問がある場合は Lock を使用すると、他のスレッドが配列を解放したことを確認できます。

lock (array1)
{
}

http://msdn.microsoft.com/en-us/library/c5kehkcz(VS.71).aspx

于 2010-02-19T01:03:46.710 に答える
0

メイン スレッドで配列のコピーを作成していない限り、何もする必要はないと思います。ワーカー スレッドが終了するまで待ちます。

于 2010-02-19T01:06:47.737 に答える