boost | 线程与并发(一)atomic
目錄
一、并發與并行
二、原子操作
三、atomic
1.創建atomic對象
2.存取atomic內部的值
3.交換值
(1)exchange()
(2)compare_exchange_weak()和compare_exchange_strong()
4.storage()
?5.整數用法
(1)atomic<int>
(2)atomic<bool>
四、并發順序?致性
一、并發與并行
并發:一個處理器上跑一個進程(多個線程),輪流啟用時間片。
并行:多個處理器同時各跑一個線程/進程。
生動講解可看當我們在說“并發、多線程”,說的是什么? - 知乎 (zhihu.com)
二、原子操作
????????所謂的原子操作,取的就是“原子是最小的、不可分割的最小個體”的意義,它表示在多個線程訪問同一個全局資源的時候,能夠確保所有其他的線程都不在同一時間內訪問相同的資源。也就是他確保了在同一時刻只有唯一的線程對這個資源進行訪問。這有點類似互斥對象對共享資源的訪問的保護,但是原子操作更加接近底層,因而效率更高。
????????在以往的C++標準中并沒有對原子操作進行規定,我們往往是使用匯編語言,或者是借助第三方的線程庫,例如intel的pthread來實現。在新標準C++11,引入了原子操作的概念,并通過這個新的頭文件提供了多種原子操作數據類型,例如,atomic_bool,atomic_int等等,如果我們在多個線程中對這些類型的共享資源進行操作,編譯器將保證這些操作都是原子性的,也就是說,確保任意時刻只有一個線程對這個資源進行訪問,編譯器將保證,多個線程訪問這個共享資源的正確性。從而避免了鎖的使用,提高了效率。
三、atomic
????????atomic實現了C++標準定義的原?操作庫(C++11.29),它封裝了不同計算機硬件的底層操作原語,提供了跨平臺的原?操作功能,讓我們完全擺脫了并發競爭讀寫變量的困擾。
????????atomic庫定義了基本模板類atomic<T>, atomic可以把對類型T的操作原?化,但不是任意的類型都可以原?化的,類型T如下:
- 標量類型(scalar),如C++內建的算術類型、枚舉、指針。
- 只有平凡(trivial)拷?/轉移構造、賦值和析構函數的類,并且可以使?memcmp執??較操 作——通常這樣的類都是POD。
????????atomic<T>還針對整數類型和指針類型進?了特化,增加了?些特殊的操作:fetch_xxx。
????????為了?便使?,atomic庫還為這些原?化的整數和指針類型定義了typedef,它們的名字都以 “atomic_”為前綴(注意沒有float和double)。
typedef atomic< char > atomic_char; typedef atomic< unsigned char > atomic_uchar; typedef atomic< signed char > atomic_schar; typedef atomic< uint8_t > atomic_uint8_t; typedef atomic< int8_t > atomic_int8_t; typedef atomic< unsigned short > atomic_ushort; typedef atomic< short > atomic_short; typedef atomic< uint16_t > atomic_uint16_t; typedef atomic< int16_t > atomic_int16_t; typedef atomic< unsigned int > atomic_uint; typedef atomic< int > atomic_int; typedef atomic< uint32_t > atomic_uint32_t; typedef atomic< int32_t > atomic_int32_t; typedef atomic< unsigned long > atomic_ulong; typedef atomic< long > atomic_long; typedef atomic< uint64_t > atomic_uint64_t; typedef atomic< int64_t > atomic_int64_t; ...????????atomic的?部分成員函數返回的都不是左值,這意味著它與?原?化的類型有明顯的不同。
1.創建atomic對象
? ? ? ? 有兩種?式創建atomic對象:
- 有參數的構造函數創建有初值的atomic;
- ?參數的默認構造函數創建?個初值不確定的atomic(這種?式很危險,我們應當盡量避免。與標準庫不同:標準庫提供atomic_init函數可初始化對象)
2.存取atomic內部的值
????????atomic最重要的兩個成員函數是store()和load(),它們以原?的?式存取atomic內部的值,不會因并發訪問導致數據不?致。atomic還使?操作符重載簡化了store()和load()的調??式:賦值等價于store(),?隱式類型轉換則等價于load()。
#include <boost/atomic.hpp>boost::atomic_int c(20);//store loadc.store(5, boost::memory_order_seq_cst);std::cout << "隱式類型轉換:" << c << std::endl; //隱式類型轉換,相當于c.load()std::cout << "使用load()取值:" << c.load() << std::endl;//結果://隱式類型轉換:5//使用load()取值:53.交換值
(1)exchange()
? ? ? 對于exchange()函數,顧名思義,它原?化地“交換”兩個值,在存值之后返回內部原有的值。
std::cout << "exchange前的值:" << c.exchange(15) << std::endl;std::cout << "exchange后的值:" << c << std::endl;//exchange前的值:5//exchange后的值:15(2)compare_exchange_weak()和compare_exchange_strong()
????????compare_exchange_weak()和compare_exchange_strong()是exchange()的增強版本,也就是常說的CAS(compare-and-swap)操作。它們?較expected,如果相等則存值為 desired,返回true/false表示原值是否被修改,但?論怎樣,最后在expected變量?都會輸出原 值。
????????兩者的區別是compare_exchange_weak()的執?速度快,但使?它即使執?成功也可能 會返回false。
int expected = 14;bool ischange = c.compare_exchange_weak(expected, 16);if (ischange){std::cout << "compare_exchange_weak后的值:" << c << std::endl;}else {std::cout << "compare_exchange_weak failed" << std::endl;}std::cout << "expected:" << expected << std::endl;//compare_exchange_weak failed//expected:15 expected = 15;ischange = c.compare_exchange_strong(expected, 16);if (ischange){std::cout << "compare_exchange_strong后的值:" << c << std::endl;}else {std::cout << "compare_exchange_strong failed" << std::endl;}std::cout << "expected:" << expected << std::endl;//compare_exchange_strong后的值:16//expected:154.storage()
????????atomic的成員函數storage()可以直接獲得atomic內部值的引?,它能夠以任意?式操作數據, 但它也因此?法提供原?保證,在并發環境?我們盡量不要使?它。使用時需要添加宏定義:
#define BOOST_ATOMIC_SILENCE_STORAGE_DEPRECATION?5.整數用法
????????整數和bool類型是程序中最常?的數據類型,原?化后的atomic<I>和atomic<bool>的?法和原始類型類似,可以安全地將它們?在并發環境?,它們能夠被多個CPU核?或線程并發訪問? ?須特意使?保護?段,從?擔當計數器或標志位的??。
(1)atomic<int>
????????atomic<I>是?類特殊的atomic對象,它除了具有基本的原?操作,還有整數特有的?些 fetch_xxx操作,它可以執?對應的數學運算,然后返回原值?不是運算后的值。atomic<I>也 重載了“++”“+=”等操作符,這些操作符重載函數內部調?了fetch_xxx函數,但返回運算后的值。
boost::atomic<int> d(100);int value = d.fetch_add(1);std::cout <<"原值:"<< value << std::endl;std::cout <<"fetch_add后的值:"<< d << std::endl;value = ++d;std::cout <<"前置++后的值:"<< value << std::endl;//原值:100//fetch_add后的值:101//前置++后的值:102(2)atomic<bool>
????????atomic<bool>?atomic<I>更特殊?些,雖然它也屬于整數,但它只有true/false兩個取值,所以它沒有fetch_xxx操作,也沒有操作符重載,其接?與基本的atomic<T>相同(但內部實現不同)。
boost::atomic<bool> _bool(false);auto x = _bool.exchange(true);std::cout <<"原值:"<< x << std::endl;std::cout <<"exchange后的值:"<< _bool << std::endl;//原值:0//exchange后的值:1四、并發順序?致性
?(可參考文章:C++ 原子操作(6種原子順序)_小烏龜的博客-CSDN博客_c++ 原子操作)
????????在現代多CPU核?并發的環境?,編譯器和CPU的優化都有可能打亂指令的執?順序,雖然這可能會獲得更?的執?效率,但也可能產?副作?,導致程序的流程不?定按照代碼的順序執?。
????????atomic庫在頭?件<boost/memory_order.hpp>?定義了內存訪問順序的概念,它是?個簡單的枚舉類型,允許?戶??控制代碼順序的?致性。
????????atomic<T>的每個成員函數都有?個memory_order默認參數(操作符重載函數除 外),它指定了原?操作的內存訪問順序要求。 memory_order參數的默認值是memory_order_seq_cst,它是最嚴格的順序?致性的約束,不允許編譯器或CPU核?為優化?調整代碼或指令的執?順序,保證在并發環境?任何CPU核?“看到”的指令順序都是相同的,其程序的執?與單CPU單線程時相同,簡化了程序員的?作。
enum class memory_order : unsigned int {relaxed = 0,consume = 1,acquire = 2,release = 4,acq_rel = 6, // acquire | releaseseq_cst = 14 // acq_rel | 8 };總結
以上是生活随笔為你收集整理的boost | 线程与并发(一)atomic的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【JY】橡胶支座的简述和其力学性能计算
- 下一篇: 广西事业单位职称免计算机,2020广西事