4

openmpタスクによって処理される要素の配列があります。タスクが配列の最後に新しい要素を追加する可能性があります。もちろん、これらの要素も処理する必要があり、新しいアイテムを生成する可能性があります。現在、このコードを使用しています

int p;
#pragma omp critical
{
    p=l.n++;
}

これは、配列の最後に場所を予約するだけです。タイプl

struct list
{
    int n;
    double *e;
}

新しい要素をp格納する場所へのインデックスとして使用されます。クリティカル領域を使わずにこの操作を実行する方法があるかどうか疑問に思いました。値をコピーしてから元の値をアトミックにインクリメントするアセンブリ命令はありますか?

コードはnehalemcpuで実行されるため、古いマシンについて心配する必要はありません。

4

3 に答える 3

6
#pragma omp atomic capture
p = l.n++;

これは、ハードウェアがサポートしている場合、値を取得する際にアトミック インクリメントを使用する必要があります。

#pragma omp atomicこの質問で詳細をお読みください: openMP、アトミック vs クリティカル?

そして、ここにIntel のドキュメントがあり#pragma omp atomicます。

私は最小限の例をコンパイルしようとしましたgcc -fopenmp -m32 -O2 -S:

int i, j;
void foo (void)
{
  #pragma omp atomic capture
  i = j++;
}

私が得たのは、単純なアトミックな「フェッチと追加」でした。これが私たちが望んでいるものです。

movl $1, %eax       # eax = 1
lock xaddl %eax, j  # atomic {swap (eax,j); j = eax + j;}
movl %eax, i        # i = eax
ret
于 2012-09-11T09:48:02.883 に答える
1

はい、x86 ではいくつかの選択肢があります。

XADD r/m, r

この命令は、第 2 オペランド (r) を第 1 オペランド (r/m) に原子的に追加し、第 2 オペランド (r) に第 1 オペランド (r/m) の元の値をロードします。

それを使用するには、2 番目のオペランドにインクリメントの量 (ここでは 1 と推測しています) をロードする必要があります。

この命令の前に LOCK プレフィックスを付ける必要があります (これによりアトミックになります)。

Microsoft Visual C++のInterlockedAdd()関数はこれを行い、AFAIR がXADD利用可能な場合は使用します (i80486 以降で利用可能)。

別の方法は、命令でループを使用することCMPXCHGです...

擬似コード:

while (true)
{
  int oldValue = l.n;
  int newValue = oldValue + 1;
  if (CAS(&l.n, newValue, oldValue) == oldValue)
    break;
}

(並行プログラミングの一般的な用語)CAS()を表す はCompare And Swap、メモリ内の値を新しい値にアトミックに置き換えようとする関数です。置換される値が最後に指定されたパラメーターと等しい場合、置換は成功しますoldValue。それ以外の場合は失敗します。CASはメモリから元の値を返します。これにより、置換が成功したかどうかがわかります (返された値を と比較しますoldValue)。失敗 (返された元の値は とは異なりますoldValue) は、読み取りと、それを別のスレッドoldValueに置き換えようとした瞬間との間に、メモリ内の値が変更されたことを示しています。newValueこの場合、手順全体を再試行するだけです。

命令はCMPXCHGx86CASです。

Microsoft Visual C++InterlockedCompareExchange()ではCMPXCHGCAS.

XADD利用できない場合は、 //InterlockedAdd()を使用して実装されます。CASCMPXCHGInterlockedCompareExchange()

他の一部の CPU では、別の可能性があります。隣接するいくつかの命令をアトミックに実行できるものもあります。

于 2012-09-11T10:14:10.317 に答える
0

これは実際には、結果を返す単なるアトミックインクリメントであり、次のようになります。

mov p, 1  ; p must be a register
lock xadd [l.n], p

そして今、あなたは知っています。実際にそれを使用する理由はわかりませんが、アセンブリコードに頼らずに使用する方法はあります。

于 2012-09-11T10:05:47.823 に答える