偶発的な共有

タスクが同じメモリー位置を使用して互いにその利用を伝えない場合、共有は偶発的です。

基本パターン

タスクがメモリー位置を読み取る前に書き込みを行い、書き込んだ値はタスク外部で読み取られることがないと仮定します。以下に例を示します。

extern int x;
// ...
ANNOTATE_SITE_BEGIN(site1);
for (i = 0; i != n; ++i) {
    ANNOTATE_ITERATION_TASK(task1);
    x = a[i];
    b[i] = x * b[i];
}
ANNOTATE_SITE_END(site1);

変数 x はタスクで読み書きされるため、タスクの複数のコピーが同時に実行されると共有の問題が発生します。次に例を示します。

  1. タスク 0 が xa[0] を設定します。

  2. タスク 1 が xa[1] を設定します。

  3. タスク 0 が x * b[0] を計算します。

興味深いことに、この共有はプログラムのロジックによって引き起こされます。ループの各反復は変数 x を使用しますが、それぞれの反復での使用は完全に独立しています。このようなメモリー位置の使用はプライベート化可能です。各タスクは個別のプライベートなメモリー位置を使用することで、プログラムの動作を変えることなく共有を排除できます。

メモリー・アロケーター

動的に割り当てられるメモリーは、偶発的な共有の特殊ケースです。次のタスクを考えてみます。

ANNOTATE_TASK_BEGIN(task2); 
Type *ptr = allocate_Type(); 
// ptr が指すオブジェクトを使用するコード 
free_Type(ptr); 
ANNOTATE_TASK_END();

allocate_Type() が、ほかのタスクで取得され解放されるのと同じアドレスを特定のタスクに返す場合、これらのタスクは同じメモリー位置をアクセスしますが、共有は偶発的です。メモリー・アロケーターは、割り当て済みで解放されていないメモリーへのポインターを返すことはありません。そのため、タスクが動的に割り当てられるメモリー位置を同時に使用することはなく、実際には共有は存在しません。

依存関係ツールは、C/C++ の new/deletemalloc/free などの標準メモリー・アロケーターを識別しますが、プログラムのカスタム・メモリー・アロケーターは認識できません。コードがカスタム・メモリー・アロケーターを使用する場合、特殊な用途の C/C++ アノテーション ANNOTATE_RECORD_ALLOCATIONANNOTATE_RECORD_DEALLOCATION を追加してそれらをマークできます。

関連情報