std:: atomic_thread_fence
|
ヘッダーで定義
<atomic>
|
||
|
extern
"C"
void
atomic_thread_fence
(
std::
memory_order
order
)
noexcept
;
|
(C++11以降) | |
memory synchronization ordering を確立します。これは非アトミックアクセスおよび緩和されたアトミックアクセスの同期順序を、 order で指定された通りに、関連するアトミック操作なしで行います。ただし、以下の説明にあるように、同期を設定するには少なくとも一つのアトミック操作が必要であることに注意してください。
目次 |
Fence-atomic 同期
スレッド
A
におけるリリースフェンス
F
は、以下の条件が満たされる場合、スレッド
B
におけるアトミックな
acquire operation
Y
と同期します (synchronizes-with)。
-
任意のメモリ順序を持つアトミックストア
Xが存在し、 -
YがXによって書き込まれた値(またはXがリリース操作であった場合、Xを先頭とするリリースシーケンス によって書き込まれる値)を読み取り、 -
スレッド
A内でFがXに対してシーケンス前に位置する。
この場合、スレッド
A
において
F
に対して
sequenced-before
関係にある全ての非アトミック操作および緩和アトミックストアは、
Y
以降にスレッド
B
で同じメモリ位置から行われる全ての非アトミック操作および緩和アトミックロードに対して
happen-before
関係が成立します。
Atomicフェンス同期
アトミックな
release操作
X
がスレッド
A
内で実行され、acquireフェンス
F
がスレッド
B
内に存在する場合、以下の条件が満たされるときに同期関係が成立します:
-
任意のメモリ順序を持つアトミック読み込み
Yが存在し、 -
YがXによって書き込まれた値(または Xが先頭となるリリースシーケンス によって書き込まれた値)を読み取り、 -
YがスレッドB内でFに対してシーケンス前に位置する。
この場合、スレッド
A
において
X
に対して
sequenced-before
関係にある全ての非アトミック操作および緩和アトミックストアは、
F
以降にスレッド
B
で同じメモリ位置から行われる全ての非アトミック操作および緩和アトミックロードに対して
happen-before
関係が成立します。
Fence-fence 同期
スレッド
A
のリリースフェンス
FA
は、スレッド
B
のアクワイアフェンス
FB
と同期する(synchronizes-with)、もし
-
アトミックオブジェクト
Mが存在し、 -
スレッド
Aにおいて、任意のメモリ順序でMを変更するアトミック書き込みXが存在し、 -
スレッド
AにおいてFAがXに対して sequenced-before の関係にあり、 -
スレッド
Bにおいて、任意のメモリ順序でのアトミック読み込みYが存在し、 -
YがXによって書き込まれた値(またはXがリリース操作であった場合のXを先頭とするリリースシーケンス によって書き込まれる値)を読み取り、 -
スレッド
BにおいてYがFBに対して sequenced-before の関係にある。
この場合、スレッド
A
において
FA
に対して
sequenced-before
関係にあるすべての非アトミック操作および緩和アトミックストアは、
happen-before
関係となり、スレッド
B
が
FB
以降に同じメモリ位置から行うすべての非アトミック操作および緩和アトミックロードに対して先行します。
order パラメータの値に応じて、この呼び出しの効果は以下の通りです:
- order == std:: memory_order_relaxed の場合、効果はありません。
- order == std:: memory_order_acquire または order == std:: memory_order_consume の場合、acquireフェンスとなります。
- order == std:: memory_order_release の場合、releaseフェンスとなります。
- order == std:: memory_order_acq_rel の場合、releaseフェンスかつacquireフェンスの両方となります。
- order == std:: memory_order_seq_cst の場合、逐次一貫順序のacquireフェンスかつreleaseフェンスとなります。
パラメータ
| order | - | このフェンスによって実行されるメモリ順序 |
注記
x86(x86-64を含む)では、
atomic_thread_fence
関数はCPU命令を発行せず、コンパイル時のコード移動にのみ影響します。ただし、
std
::
atomic_thread_fence
(
std::
memory_order_seq_cst
)
は除きます。
atomic_thread_fence
は同じ
std::memory_order
を持つアトミックストア操作よりも強い同期制約を課します。アトミックストア・リリース操作は先行する全ての読み書きがストア・リリースを超えて移動するのを防ぎますが、
atomic_thread_fence
に
std::
memory_order_release
順序付けを指定した場合、先行する全ての読み書きが後続の全てのストアを超えて移動するのを防ぎます。
Fence-fence同期は、一連の複数の緩和されたアトミック操作に同期を追加するために使用できます。例えば:
// グローバル std::string computation(int); void print(std::string); std::atomic<int> arr[3] = {-1, -1, -1}; std::string data[1000]; //非アトミックデータ // スレッドA、3つの値を計算 void ThreadA(int v0, int v1, int v2) { // assert(0 <= v0, v1, v2 < 1000); data[v0] = computation(v0); data[v1] = computation(v1); data[v2] = computation(v2); std::atomic_thread_fence(std::memory_order_release); std::atomic_store_explicit(&arr[0], v0, std::memory_order_relaxed); std::atomic_store_explicit(&arr[1], v1, std::memory_order_relaxed); std::atomic_store_explicit(&arr[2], v2, std::memory_order_relaxed); } // スレッドB、既に計算された0〜3個の値を出力 void ThreadB() { int v0 = std::atomic_load_explicit(&arr[0], std::memory_order_relaxed); int v1 = std::atomic_load_explicit(&arr[1], std::memory_order_relaxed); int v2 = std::atomic_load_explicit(&arr[2], std::memory_order_relaxed); std::atomic_thread_fence(std::memory_order_acquire); // v0, v1, v2は-1になる可能性、一部または全てが設定される可能性がある // それ以外の場合、フェンスにより非アトミックデータを安全に読み取ることができる: if (v0 != -1) print(data[v0]); if (v1 != -1) print(data[v1]); if (v2 != -1) print(data[v2]); }
例
メールボックスの配列をスキャンし、自宛てのもののみを不必要な同期なしで処理します。 この例ではアトミックフェンス同期を使用しています。
const int num_mailboxes = 32; std::atomic<int> mailbox_receiver[num_mailboxes]; std::string mailbox_data[num_mailboxes]; // 書き込みスレッドは非アトミックな共有データを更新し、 // その後以下のようにmailbox_receiver[i]を更新する: mailbox_data[i] = ...; std::atomic_store_explicit(&mailbox_receiver[i], receiver_id, std::memory_order_release); // 読み込みスレッドは全てのmailbox[i]をチェックする必要があるが、同期は1つだけで十分 for (int i = 0; i < num_mailboxes; ++i) if (std::atomic_load_explicit(&mailbox_receiver[i], std::memory_order_relaxed) == my_id) { // 1つの書き込みスレッドとのみ同期 std::atomic_thread_fence(std::memory_order_acquire); // atomic_store_explicit()の前に書き込みスレッドで行われた全ての操作を // 確実に観測できることが保証される do_work(mailbox_data[i]); }
関連項目
|
(C++11)
|
指定されたアトミック操作に対するメモリ順序制約を定義する
(列挙型) |
|
(C++11)
|
同じスレッド内で実行されるスレッドとシグナルハンドラ間のフェンス
(関数) |
|
Cドキュメント
for
atomic_thread_fence
|
|