2

ブーストアトミックのドキュメントを調べていたところ、次の例に出くわしました。

atomic<int> a(0);

thread1:
  ... /* A */
  a.fetch_add(1, memory_order_release);

thread2:
  int tmp = a.load(memory_order_acquire);
  if (tmp == 1) 
  {
    ... /* B */
  } 
  else 
  {
    ... /* C */
  }

今でも memory_order_release と memory_order_acquire に関して少し混乱しています。ドキュメントでは、次のように説明されています。

memory_order_release

解除操作を行ってください。非公式に言えば、先行するすべてのメモリ操作がこの時点を過ぎて並べ替えられるのを防ぎます。

memory_order_acquire

取得操作を実行します。非公式に言えば、この時点より前に後続のメモリ操作が並べ替えられるのを防ぎます。

これらの例でさえ、私はまだ少し混乱しています。誰かが上記の定義の意味と、A と C がどのように競合するのかを説明していただければ幸いです。

4

1 に答える 1

2

これらの定義は、ストアの後に A のメモリ操作を並べ替えることができないことを意味します(問題の解放aの定義)。また、B または C の操作はいずれも、他のスレッドでのロードに先行することはできません(問題の獲得の定義)。a

aここで、この例では、 を操作するコード、または少なくとも に書き込むコードは他にないと仮定していますa。B が実行されaた場合、ロードがtmp発生したときに値が 1 だったことを意味します。aが値 1 を持つには、前fetch_addに が実行されている ( が とfetch_add同期するload) 必要がありました。これは、 A のコードが実行を完了したことを意味します。その特定のコード パスにヒットした場合、操作の順序は次のようになります。

A
a.fetch_add(1,memory_order_release);
int tmp = a.load(memory_order_acquire);
B

これはload、最初のスレッドが を実行できなかったことを意味しますがfetch_add、どこで実行されているかについての保証はありません。スレッド 2 が C を実行するまでに、A はまだ実行されている可能性があります (または、まだ開始されていないか、完了している可能性があります)。

A と B の両方が同じ変数にアクセスする場合、A が完了した後にのみ B を実行できることがアトミックによって保証されるため、競合は発生しません。一方、C についてはその保証が与えられていないため、A と C が同じ変数にアクセスし、そのうちの少なくとも 1 つがそれに書き込みを行った場合、競合状態が発生します。

于 2013-11-03T03:36:17.600 に答える