前面我們講了C++11下的多線程及相關操作咬清,這些操作在絕大多數(shù)情況下應該夠用了谢澈。但在某些極端場合洒嗤,如需要高性能的情況下院尔,我們還需要一些更高效的同步手段蜻展。本節(jié)介紹的原子操作是一種lock free的操作,不需要同步鎖邀摆,具有很高的性能纵顾。在化學中原子不是可分割的最小單位,引申到編程中栋盹,原子操作是不可打斷的最低粒度操作施逾,是線程安全的。C++11中原子類提供的成員函數(shù)都是原子的例获,是線程安全的音念。
原子操作中最簡單的莫過于atomic_flag,只有兩種操作:test and set躏敢、clear闷愤。我們的原子操作就從這種類型開始。
1. std::atomic_flag
C++11中所有的原子類都是不允許拷貝件余、不允許Move的讥脐,atomic_flag也不例外遭居。atomic_flag顧名思議,提供了標志的管理旬渠,標志有三種狀態(tài):clear俱萍、set和未初始化狀態(tài)。
1.1 atomic_flag實例化
缺省情況下atomic_flag處于未初始化狀態(tài)告丢。除非初始化時使用了ATOMIC_FLAG_INIT
宏枪蘑,則此時atomic_flag處于clear狀態(tài)。
1.2 std::atomic_flag::clear
調用該函數(shù)將會把atomic_flag置為clear狀態(tài)岖免。clear狀態(tài)您可以理解為bool類型的false岳颇,set狀態(tài)可理解為true狀態(tài)。clear函數(shù)沒有任何返回值:
void clear(memory_order m = memory_order_seq_cst) volatile noexcept;
void clear(memory_order m = memory_order_seq_cst) noexcept;
對于memory_order我們會在后面的章節(jié)中詳細介紹它颅湘,現(xiàn)在先列出其取值及簡單釋義
序號 | 值 | 意義 |
---|---|---|
1 | memory_order_relaxed | 寬松模型话侧,不對執(zhí)行順序做保證 |
2 | memory_order_consume | 當前線程中,滿足happens-before原則。 當前線程中該原子的所有后續(xù)操作,必須在本條操作完成之后執(zhí)行 |
3 | memory_order_acquire | 當前線程中,讀操作滿足happens-before原則闯参。 所有后續(xù)的讀操作必須在本操作完成后執(zhí)行 |
4 | memory_order_release | 當前線程中,寫操作滿足happens-before原則瞻鹏。 所有后續(xù)的寫操作必須在本操作完成后執(zhí)行 |
5 | memory_order_acq_rel | 當前線程中,同時滿足memory_order_acquire和memory_order_release |
6 | memory_order_seq_cst | 最強約束鹿寨。全部讀寫都按順序執(zhí)行 |
1.3 test_and_set
該函數(shù)會檢測flag是否處于set狀態(tài)新博,如果不是,則將其設置為set狀態(tài)脚草,并返回false赫悄;否則返回true。
test_and_set是典型的read-modify-write(RMW)模型玩讳,保證多線程環(huán)境下只被設置一次。下面代碼通過10個線程嚼贡,模擬了一個計數(shù)程序熏纯,第一個完成計數(shù)的會打印"win"。
#include <atomic> // atomic_flag
#include <iostream> // std::cout, std::endl
#include <list> // std::list
#include <thread> // std::thread
void race(std::atomic_flag &af, int id, int n) {
for (int i = 0; i < n; i++) {
}
// 第一個完成計數(shù)的打釉敛摺:Win
if (!af.test_and_set()) {
printf("%s[%d] win!!!\n", __FUNCTION__, id);
}
}
int main() {
std::atomic_flag af = ATOMIC_FLAG_INIT;
std::list<std::thread> lstThread;
for (int i = 0; i < 10; i++) {
lstThread.emplace_back(race, std::ref(af), i + 1, 5000 * 10000);
}
for (std::thread &thr : lstThread) {
thr.join();
}
return 0;
}
程序輸出如下(每次運行樟澜,可能率先完成的thread不同):
race[7] win!!!
上一篇 C++11多線程-線程局部存儲 |
目錄 | 下一篇 C++11多線程-原子操作(2) |
---|