std::atomic_thread_fence
定義於標頭檔案 <atomic> |
||
extern "C" void atomic_thread_fence( std::memory_order order ) noexcept; |
(C++11 起) | |
根據 `order` 引數的要求,在不關聯原子操作的情況下建立非原子和寬鬆原子訪問的記憶體同步順序。然而,請注意,至少需要一個原子操作來設定同步,如下所述。
目錄 |
[編輯] 柵欄-原子同步
如果滿足以下條件,執行緒 A 中的釋放柵欄 F 與執行緒 B 中的原子獲取操作 Y 同步:
- 存在一個原子儲存 X(具有任何記憶體順序),
- Y 讀取 X 寫入的值(或者如果 X 是釋放操作,則為以 X 為首的釋放序列將寫入的值),
- 線上程 A 中,F 在 X 之前排序。
在這種情況下,線上程 A 中在 F 之前排序的所有非原子和寬鬆原子儲存,將線上程 B 中在 Y 之後從相同位置進行的所有非原子和寬鬆原子載入 之前發生。
[編輯] 原子-柵欄同步
如果滿足以下條件,執行緒 A 中的原子釋放操作 X 與執行緒 B 中的獲取柵欄 F 同步:
- 存在一個原子讀取 Y(具有任何記憶體順序),
- Y 讀取 X 寫入的值(或以 X 為首的釋放序列寫入的值),
- 線上程 B 中,Y 在 F 之前排序。
在這種情況下,線上程 A 中在 X 之前排序的所有非原子和寬鬆原子儲存,將線上程 B 中在 F 之後從相同位置進行的所有非原子和寬鬆原子載入 之前發生。
[編輯] 柵欄-柵欄同步
如果滿足以下條件,執行緒 A 中的釋放柵欄 FA 與執行緒 B 中的獲取柵欄 FB 同步:
- 存在一個原子物件 M,
- 存在一個原子寫入 X(具有任何記憶體順序),它線上程 A 中修改 M,
- 線上程 A 中,FA 在 X 之前排序,
- 線上程 B 中存在一個原子讀取 Y(具有任何記憶體順序),
- Y 讀取 X 寫入的值(或者如果 X 是釋放操作,則為以 X 為首的釋放序列將寫入的值),
- 線上程 B 中,Y 在 FB 之前排序。
在這種情況下,線上程 A 中在 FA 之前排序的所有非原子和寬鬆原子儲存,將線上程 B 中在 FB 之後從相同位置進行的所有非原子和寬鬆原子載入 之前發生。
[編輯] 引數
順序 | - | 此柵欄執行的記憶體排序 |
[編輯] 返回值
(無)
[編輯] 注意
在 x86(包括 x86-64)上,`atomic_thread_fence` 函式不發出 CPU 指令,僅影響編譯時程式碼移動,除了 std::atomic_thread_fence(std::memory_order_seq_cst)。
`atomic_thread_fence` 施加的同步約束比具有相同 std::memory_order 的原子儲存操作更強。原子儲存-釋放操作阻止所有之前的讀寫操作越過儲存-釋放,而帶有 std::memory_order_release 順序的 `atomic_thread_fence` 阻止所有之前的讀寫操作越過所有隨後的儲存。
柵欄-柵欄同步可用於為一系列寬鬆原子操作新增同步,例如
// Global std::string computation(int); void print(std::string); std::atomic<int> arr[3] = {-1, -1, -1}; std::string data[1000]; //non-atomic data // Thread A, compute 3 values. 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); } // Thread B, prints between 0 and 3 values already computed. 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 might turn out to be -1, some or all of them. // Otherwise it is safe to read the non-atomic data because of the fences: 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]; // The writer threads update non-atomic shared data // and then update mailbox_receiver[i] as follows: mailbox_data[i] = ...; std::atomic_store_explicit(&mailbox_receiver[i], receiver_id, std::memory_order_release); // Reader thread needs to check all mailbox[i], but only needs to sync with one. for (int i = 0; i < num_mailboxes; ++i) if (std::atomic_load_explicit(&mailbox_receiver[i], std::memory_order_relaxed) == my_id) { // synchronize with just one writer std::atomic_thread_fence(std::memory_order_acquire); // guaranteed to observe everything done in the writer thread // before the atomic_store_explicit() do_work(mailbox_data[i]); }
[編輯] 另請參閱
(C++11) |
定義給定原子操作的記憶體排序約束 (enum) |
(C++11) |
執行緒與在同一執行緒中執行的訊號處理程式之間的屏障 (function) |
C 文件 for atomic_thread_fence
|