日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++11 并发指南六(atomic 类型详解一 atomic_flag 介绍)

發(fā)布時間:2025/3/15 c/c++ 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++11 并发指南六(atomic 类型详解一 atomic_flag 介绍) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

C++11 并發(fā)指南已經(jīng)寫了 5 章,前五章重點介紹了多線程編程方面的內(nèi)容,但大部分內(nèi)容只涉及多線程、互斥量、條件變量和異步編程相關(guān)的 API,C++11 程序員完全可以不必知道這些 API 在底層是如何實現(xiàn)的,只需要清楚 C++11 多線程和異步編程相關(guān) API 的語義,然后熟加練習即可應付大部分多線程編碼需求。但是在很多極端的場合下為了性能和效率,我們需要開發(fā)一些 lock-free 的算法和數(shù)據(jù)結(jié)構(gòu),前面幾章的內(nèi)容可能就派不上用場了,因此從本文開始介紹 C++11 標準中 <atomic> 頭文件里面的類和相關(guān)函數(shù)。

本文介紹 <atomic> 頭文件中最簡單的原子類型: atomic_flag。atomic_flag 一種簡單的原子布爾類型,只支持兩種操作,test-and-set 和 clear。

std::atomic_flag 構(gòu)造函數(shù)

std::atomic_flag 構(gòu)造函數(shù)如下:

  • atomic_flag() noexcept = default;
  • atomic_flag (const atomic_flag&T) = delete;

std::atomic_flag 只有默認構(gòu)造函數(shù),拷貝構(gòu)造函數(shù)已被禁用,因此不能從其他的 std::atomic_flag 對象構(gòu)造一個新的 std::atomic_flag 對象。

如果在初始化時沒有明確使用 ATOMIC_FLAG_INIT初始化,那么新創(chuàng)建的 std::atomic_flag 對象的狀態(tài)是未指定的(unspecified)(既沒有被 set 也沒有被 clear。)另外,atomic_flag不能被拷貝,也不能 move 賦值。

ATOMIC_FLAG_INIT: 如果某個 std::atomic_flag 對象使用該宏初始化,那么可以保證該 std::atomic_flag 對象在創(chuàng)建時處于 clear 狀態(tài)。

下面先看一個簡單的例子,main() 函數(shù)中創(chuàng)建了 10 個線程進行計數(shù),率先完成計數(shù)任務的線程輸出自己的 ID,后續(xù)完成計數(shù)任務的線程不會輸出自身 ID:

#include <iostream> // std::cout #include <atomic> // std::atomic, std::atomic_flag, ATOMIC_FLAG_INIT #include <thread> // std::thread, std::this_thread::yield #include <vector> // std::vector std::atomic<bool> ready(false); // can be checked without being set std::atomic_flag winner = ATOMIC_FLAG_INIT; // always set when checkedvoid count1m(int id) {while (!ready) {std::this_thread::yield();} // 等待主線程中設置 ready 為 true.for (int i = 0; i < 1000000; ++i) {} // 計數(shù).// 如果某個線程率先執(zhí)行完上面的計數(shù)過程,則輸出自己的 ID.// 此后其他線程執(zhí)行 test_and_set 是 if 語句判斷為 false,// 因此不會輸出自身 ID.if (!winner.test_and_set()) {std::cout << "thread #" << id << " won!\n";} };int main() {std::vector<std::thread> threads;std::cout << "spawning 10 threads that count to 1 million...\n";for (int i = 1; i <= 10; ++i)threads.push_back(std::thread(count1m, i));ready = true;for (auto & th:threads)th.join();return 0; }

多次執(zhí)行結(jié)果如下:

atomic ) ./Atomic-Flag1 spawning 10 threads that count to 1 million... thread #6 won! atomic ) ./Atomic-Flag1 spawning 10 threads that count to 1 million... thread #1 won! atomic ) ./Atomic-Flag1 spawning 10 threads that count to 1 million... thread #5 won! atomic ) ./Atomic-Flag1 spawning 10 threads that count to 1 million... thread #1 won! atomic ) ./Atomic-Flag1 spawning 10 threads that count to 1 million... thread #1 won! atomic ) ./Atomic-Flag1 spawning 10 threads that count to 1 million... thread #10 won!

std::atomic_flag::test_and_set 介紹

std::atomic_flag 的 test_and_set 函數(shù)原型如下:

bool test_and_set (memory_order sync = memory_order_seq_cst) volatile noexcept; bool test_and_set (memory_order sync = memory_order_seq_cst) noexcept;

test_and_set() 函數(shù)檢查 std::atomic_flag 標志,如果 std::atomic_flag 之前沒有被設置過,則設置 std::atomic_flag 的標志,并返回先前該 std::atomic_flag 對象是否被設置過,如果之前 std::atomic_flag 對象已被設置,則返回 true,否則返回 false。

test-and-set 操作是原子的(因此 test-and-set 是原子 read-modify-write (RMW)操作)。

test_and_set 可以指定 Memory Order(后續(xù)的文章會詳細介紹 C++11 的 Memory Order,此處為了完整性列出 test_and_set 參數(shù) sync 的取值),取值如下:

?

Memory Order 值Memory Order 類型
memory_order_relaxedRelaxed
memory_order_consumeConsume
memory_order_acquireAcquire
memory_order_releaseRelease
memory_order_acq_relAcquire/Release
memory_order_seq_cstSequentially consistent

?一個簡單的例子:

#include <iostream> // std::cout #include <atomic> // std::atomic_flag #include <thread> // std::thread #include <vector> // std::vector #include <sstream> // std::stringstream std::atomic_flag lock_stream = ATOMIC_FLAG_INIT; std::stringstream stream;void append_number(int x) {while (lock_stream.test_and_set()) {}stream << "thread #" << x << '\n';lock_stream.clear(); }int main() {std::vector < std::thread > threads;for (int i = 1; i <= 10; ++i)threads.push_back(std::thread(append_number, i));for (auto & th:threads)th.join();std::cout << stream.str() << std::endl;;return 0; }

執(zhí)行結(jié)果如下:

thread #1 thread #2 thread #3 thread #4 thread #5 thread #6 thread #7 thread #8 thread #9 thread #10

std::atomic_flag::clear() 介紹

清除 std::atomic_flag 對象的標志位,即設置 atomic_flag 的值為 false。clear 函數(shù)原型如下:

void clear (memory_order sync = memory_order_seq_cst) volatile noexcept; void clear (memory_order sync = memory_order_seq_cst) noexcept;

清除 std::atomic_flag 標志使得下一次調(diào)用 std::atomic_flag::test_and_set 返回 false。

std::atomic_flag::clear() 可以指定 Memory Order(后續(xù)的文章會詳細介紹 C++11 的 Memory Order,此處為了完整性列出 clear 參數(shù) sync 的取值),取值如下:

?

Memory Order 值Memory Order 類型
memory_order_relaxedRelaxed
memory_order_consumeConsume
memory_order_acquireAcquire
memory_order_releaseRelease
memory_order_acq_relAcquire/Release
memory_order_seq_cstSequentially consistent

結(jié)合 std::atomic_flag::test_and_set() 和 std::atomic_flag::clear(),std::atomic_flag 對象可以當作一個簡單的自旋鎖使用,請看下例:

#include <thread> #include <vector> #include <iostream> #include <atomic>std::atomic_flag lock = ATOMIC_FLAG_INIT;void f(int n) {for (int cnt = 0; cnt < 100; ++cnt) {while (lock.test_and_set(std::memory_order_acquire)) // acquire lock; // spinstd::cout << "Output from thread " << n << '\n';lock.clear(std::memory_order_release); // release lock } }int main() {std::vector<std::thread> v;for (int n = 0; n < 10; ++n) {v.emplace_back(f, n);}for (auto& t : v) {t.join();} }

在上面的程序中,std::atomic_flag 對象 lock 的上鎖操作可以理解為 lock.test_and_set(std::memory_order_acquire); (此處指定了 Memory Order,更多有關(guān) Memory Order 的概念,我會在后續(xù)的文章中介紹),解鎖操作相當與 lock.clear(std::memory_order_release)。

在上鎖的時候,如果 lock.test_and_set 返回 false,則表示上鎖成功(此時 while 不會進入自旋狀態(tài)),因為此前 lock 的標志位為 false(即沒有線程對 lock 進行上鎖操作),但調(diào)用 test_and_set 后 lock 的標志位為 true,說明某一線程已經(jīng)成功獲得了 lock 鎖。

如果在該線程解鎖(即調(diào)用 lock.clear(std::memory_order_release)) 之前,另外一個線程也調(diào)用 lock.test_and_set(std::memory_order_acquire) 試圖獲得鎖,則 test_and_set(std::memory_order_acquire) 返回 true,則 while 進入自旋狀態(tài)。如果獲得鎖的線程解鎖(即調(diào)用了 lock.clear(std::memory_order_release))之后,某個線程試圖調(diào)用 lock.test_and_set(std::memory_order_acquire) 并且返回 false,則 while 不會進入自旋,此時表明該線程成功地獲得了鎖。

按照上面的分析,我們知道在某種情況下 std::atomic_flag 對象可以當作一個簡單的自旋鎖使用。

總結(jié)

以上是生活随笔為你收集整理的C++11 并发指南六(atomic 类型详解一 atomic_flag 介绍)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。