国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
C++11 并發(fā)指南六(atomic 類型詳解一 atomic
C++11 并發(fā)指南已經(jīng)寫了 5 章,前五章重點(diǎn)介紹了多線程編程方面的內(nèi)容,但大部分內(nèi)容只涉及多線程、互斥量、條件變量和異步編程相關(guān)的 API,C++11 程序員完全可以不必知道這些 API 在底層是如何實(shí)現(xiàn)的,只需要清楚 C++11 多線程和異步編程相關(guān) API 的語義,然后熟加練習(xí)即可應(yīng)付大部分多線程編碼需求。但是在很多極端的場(chǎng)合下為了性能和效率,我們需要開發(fā)一些 lock-free 的算法和數(shù)據(jù)結(jié)構(gòu),前面幾章的內(nèi)容可能就派不上用場(chǎng)了,因此從本文開始介紹 C++11 標(biāo)準(zhǔn)中 <atomic> 頭文件里面的類和相關(guān)函數(shù)。
本文介紹 <atomic> 頭文件中最簡(jiǎn)單的原子類型: atomic_flag。atomic_flag 一種簡(jiǎn)單的原子布爾類型,只支持兩種操作,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 只有默認(rèn)構(gòu)造函數(shù),拷貝構(gòu)造函數(shù)已被禁用,因此不能從其他的 std::atomic_flag 對(duì)象構(gòu)造一個(gè)新的 std::atomic_flag 對(duì)象。
如果在初始化時(shí)沒有明確使用 ATOMIC_FLAG_INIT初始化,那么新創(chuàng)建的 std::atomic_flag 對(duì)象的狀態(tài)是未指定的(unspecified)(既沒有被 set 也沒有被 clear。)另外,atomic_flag不能被拷貝,也不能 move 賦值。
ATOMIC_FLAG_INIT: 如果某個(gè) std::atomic_flag 對(duì)象使用該宏初始化,那么可以保證該 std::atomic_flag 對(duì)象在創(chuàng)建時(shí)處于 clear 狀態(tài)。
下面先看一個(gè)簡(jiǎn)單的例子,main() 函數(shù)中創(chuàng)建了 10 個(gè)線程進(jìn)行計(jì)數(shù),率先完成計(jì)數(shù)任務(wù)的線程輸出自己的 ID,后續(xù)完成計(jì)數(shù)任務(wù)的線程不會(huì)輸出自身 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::vectorstd::atomic<bool> ready(false); // can be checked without being setstd::atomic_flag winner = ATOMIC_FLAG_INIT; // always set when checkedvoid count1m(int id){ while (!ready) { std::this_thread::yield(); } // 等待主線程中設(shè)置 ready 為 true. for (int i = 0; i < 1000000; ++i) { } // 計(jì)數(shù). // 如果某個(gè)線程率先執(zhí)行完上面的計(jì)數(shù)過程,則輸出自己的 ID. // 此后其他線程執(zhí)行 test_and_set 是 if 語句判斷為 false, // 因此不會(huì)輸出自身 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 標(biāo)志,如果 std::atomic_flag 之前沒有被設(shè)置過,則設(shè)置 std::atomic_flag 的標(biāo)志,并返回先前該 std::atomic_flag 對(duì)象是否被設(shè)置過,如果之前 std::atomic_flag 對(duì)象已被設(shè)置,則返回 true,否則返回 false。
test-and-set 操作是原子的(因此 test-and-set 是原子 read-modify-write (RMW)操作)。
test_and_set 可以指定 Memory Order(后續(xù)的文章會(huì)詳細(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
一個(gè)簡(jiǎn)單的例子:
#include <iostream> // std::cout#include <atomic> // std::atomic_flag#include <thread> // std::thread#include <vector> // std::vector#include <sstream> // std::stringstreamstd::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 #1thread #2thread #3thread #4thread #5thread #6thread #7thread #8thread #9thread #10
std::atomic_flag::clear() 介紹
清除 std::atomic_flag 對(duì)象的標(biāo)志位,即設(shè)置 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 標(biāo)志使得下一次調(diào)用 std::atomic_flag::test_and_set 返回 false。
std::atomic_flag::clear() 可以指定 Memory Order(后續(xù)的文章會(huì)詳細(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 對(duì)象可以當(dāng)作一個(gè)簡(jiǎn)單的自旋鎖使用,請(qǐng)看下例:
#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 ; // spin std::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 對(duì)象 lock 的上鎖操作可以理解為 lock.test_and_set(std::memory_order_acquire); (此處指定了 Memory Order,更多有關(guān) Memory Order 的概念,我會(huì)在后續(xù)的文章中介紹),解鎖操作相當(dāng)與 lock.clear(std::memory_order_release)。
在上鎖的時(shí)候,如果 lock.test_and_set 返回 false,則表示上鎖成功(此時(shí) while 不會(huì)進(jìn)入自旋狀態(tài)),因?yàn)榇饲?lock 的標(biāo)志位為 false(即沒有線程對(duì) lock 進(jìn)行上鎖操作),但調(diào)用 test_and_set 后 lock 的標(biāo)志位為 true,說明某一線程已經(jīng)成功獲得了 lock 鎖。
如果在該線程解鎖(即調(diào)用 lock.clear(std::memory_order_release)) 之前,另外一個(gè)線程也調(diào)用 lock.test_and_set(std::memory_order_acquire) 試圖獲得鎖,則 test_and_set(std::memory_order_acquire) 返回 true,則 while 進(jìn)入自旋狀態(tài)。如果獲得鎖的線程解鎖(即調(diào)用了 lock.clear(std::memory_order_release))之后,某個(gè)線程試圖調(diào)用 lock.test_and_set(std::memory_order_acquire) 并且返回 false,則 while 不會(huì)進(jìn)入自旋,此時(shí)表明該線程成功地獲得了鎖。
按照上面的分析,我們知道在某種情況下 std::atomic_flag 對(duì)象可以當(dāng)作一個(gè)簡(jiǎn)單的自旋鎖使用。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
深入理解C11/C 11內(nèi)存模型
c++11 atomic_flag實(shí)現(xiàn)高效的mutex
C++ 新特性學(xué)習(xí)(八) — 原子操作和多線程庫[多工內(nèi)存模型]
談?wù)?C 中的內(nèi)存順序 (Memory Order)
Understanding memory reordering
線程學(xué)習(xí)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服