C++11併發API總結

C++11 多線程相關的頭文件

  • C++ 新標準中引入了四個頭文件來支持多線程編程,他們分別是 < atomic>, < thread>, < condition_variable> 和< future>.
  • < atomic>:該頭文件主要聲明瞭兩個類,std::atomic和std::atomic_flag,另外還聲明瞭一套C分格的原子類型和與C兼容的原操作的函數.
  • < thread>:該頭文件主要聲明瞭std::thread類,另外std::this_thread命名空間也在該頭文件中.
  • < mutex>:該頭文件主要申明瞭與互斥量(mutex)相關的類,包括std::mutex系列類,std::lock_guard,std::unique_lock,以及其他類型和函數.
  • :該頭文件主要聲明瞭與條件變量相關的類,包括std::condition_variable和std::condition_variable_any.
  • < future>:該頭文件主要申明瞭std::promise,std::package_task兩個Provider類,以及std::future和std::share_future兩個Future類,另外還有一些與之相關的類型和函數,std::async()函數就聲明在此文件中.

std::thread構造函數

  • default thread() noexcept; //noexcept不會拋出異常,默認構造函數,創建一個空的thread執行對象.
  • initialization template

move賦值操作

  • move(1) thread& operator=(thread& rhs) noexcept;
  • copy delete thread operator(const thread &)=delete;
    (1)move 賦值操作,如果當前對象不可joinable,需要傳遞一個右值引用(rhs)給move賦值操作,如果當前對象可被joinable,則terminate()報錯.
    (2)拷貝賦值操作被禁用,thread 對象不可被拷貝。
    線程調用到的函數在一個類中,那必須將該函數申明爲靜態函數,因爲靜態成員函數屬於靜態全局區,線程可以共享這個區域,故可以各自調用.

< mutex>頭文件介紹

Mutex系列類(4種)

  • std::mutex,最基本的Mutex類.
  • std::recursive_mutex,遞歸Mutex類.
  • std::time_mutex,定時Mutex類.
  • std::recursive_timed_mutex,定時遞歸Mutex類.

Lock類(2種)

  • std::lock_guard,與Mutex RAII相關,方便線程對互斥量上鎖.
  • std::unique_lock,與Mutex RAII相關,方便線程對互斥量上鎖,但提供了更好的上鎖和解鎖控制.

其他類型

  • std::once_flag
  • std::adopt_lock_t
  • std::defer_lock_t
  • std::try_to_lock_t

函數

  • std::try_lock,嘗試同時對多個互斥量上鎖.
  • std::lock,可以同時對多個互斥量上鎖.
  • std::call_once,如果多個線程需要同時調用某個函數,call_once可以保證多個線程對該函數只調用一次.

std::mutex的成員函數

  • 構造函數,std::mutex不允許拷貝構造,也不允許move拷貝,最初產生的mutex對象是處於unlockeed狀態的.
  • lock(),調用線程將鎖住該互斥量,線程調用該函數會發生下面三種情況:(1)如果該互斥量當前沒有被鎖住,則調用線程將該互斥量鎖住,直到調用unlock之前,該線程一直擁有該鎖,(2)如果當前的互斥量被其他線程鎖住,則當前的調用線程被阻塞.(3)如果當前互斥量被調用線程鎖住,則會產生死鎖.
  • unlock(),解鎖,釋放對互斥量的所有權.
  • try_lock(),嘗試鎖住互斥量如果互斥量被其他線程佔有,則當前線程也不會被阻塞。線程調用該函數也會出現下面 3 種情況(1). 如果當前互斥量沒有被其他線程佔有,則該線程鎖住互斥量,直到該線程調用 unlock 釋放互斥量。(2). 如果當前互斥量被其他線程鎖住,則當前調用線程返回 false,而並不會被阻塞掉。(3).如果當前互斥量被當前調用線程鎖住,則會產生死鎖(deadlock)。

幾個與鎖類型相關的Tag類,分別如下:

  • std::adopt_lock_t,一個空的標記類,定義如下:struct adopt_lock_t{};該類型的常量對象adopt_lock(adopt_lock是一個常量對象,定義如下:constexpr adopt_lock_t adopt_lock{};通常作爲參數傳給unique_lock或lock_guard的構造函數.
  • std::defer_lock_t,一個空的標記類,定義如下:struct defer_lock_t{}; 該類型的常量對象defer_lock (defer_lock 是一個常量對象,定義如下: constexpr defer_lock_t defer_lock{}; 通常作爲參數傳給unique_lock或lock_guard的構造函數.
  • std::try_to_lock_t,一個空的標記類,定義如下: struct try_to_lock_t {}; 該類型常量對象try_to_lock(try_to_lock是一個常量對象,定義如下:constexpr try_to_lock_t try_to_lock{},通常作爲參數傳給unique_lock或lock_guard的構造函數.

std::lock_guard介紹

std::lock_gurad 是 C++11 中定義的模板類。定義如下:
template < class Mutex> class lock_guard;
lock_guard對象通常用於管理某個鎖(Lock)對象,在某個lock_guard對象的聲明週期內,它所管理的鎖對象會一直保持上鎖狀態,而lock_guar=生命週期結束後,它所管理的鎖對象會被解鎖. 模板Mutex代表互斥量類型,例如std::mutex類型,它應該是一個基本的BasicLockable類型
* 在 lock_guard 對象構造時,傳入的 Mutex 對象(即它所管理的 Mutex 對象)會被當前線程鎖住。在lock_guard 對象被析構時,它所管理的 Mutex 對象會自動解鎖,由於不需要程序員手動調用 lock 和 unlock 對 Mutex 進行上鎖和解鎖操作,因此這也是最簡單安全的上鎖和解鎖方式,尤其是在程序拋出異常後先前已被上鎖的 Mutex 對象可以正確進行解鎖操作,極大地簡化了程序員編寫與 Mutex 相關的異常處理代碼。

lock_guard 構造函數

locking(1) explicit lock_guard(mutex_type& m);
adopting(2) lock_guard(mutex_type& m,adopt_lock_t tag);
copy deleted lock_guard(const lock_guard&)=delete;
1.locking初始化:
lock_guard 對象管理Mutex對象m,並在構造時對m進行上鎖(調用m.lock()).
2.adopting初始化
lock_guard對象管理Mutex對象m,與locking初始化(1)不同的是,Mutex對象m已被當前線程鎖住.
3.拷貝構造
lock_guard對象的拷貝構造和移動構造都被禁用,因此lock_guard對象不可被拷貝構造或移動構造.

std::unique_lock介紹

  • unique_lock 對象以獨佔所有權的方式管理 mutex 對象的上鎖和解鎖操作就是沒有其他的 unique_lock 對象同時擁有某個 mutex 對象的所有權。
  • 在構造(或移動(move)賦值)時,unique_lock 對象需要傳遞一個 Mutex 對象作爲它的參數,新創建的 unique_lock 對象負責傳入的 Mutex 對象的上鎖和解鎖操作.

unique_lock 不同於lock_guard的用法.

unique_lock的構造函數

  • default(1) unique_lock noexcept;
  • locking(2) explicit unique_lock(mutex_type & m);
  • try-locking(3) unique_lock(mutex_type& m,try_to_lock_t tag);
  • deferred(4) unique_lock(mutex_tyoe& m,defer_lock_t tag) noexcept;
  • adopting(5) unique_locking(mutex_type& m,adopt_lock_t tag);
  • locking for(6) template

unique_lock移動賦值操作

  • move(1) unique_lock& operator=(unique_lock&& x)noexcept;
  • copy deleted unique_lock& operator=(const unique_lock&)=delete;
  • 移動賦值之後,由x所管理的Mutex對象及其狀態將會被新的unique_lock對象取代.
  • 如果被賦值的對象之前已經獲得了它所管理的Mutex對象的鎖,則在移動賦值之前會調用unlock函數釋放它所佔有的鎖.
  • 調用移動賦值之後,x對象如同通過默認構造函數所創建的,也就不再管理任何Mutex對象了. ### unique_lock主要成員函數
    (1)上鎖/解鎖操作:lock,try_lock,try_lock_for,try_lock_until和unlock.
    (2)修改操作:移動賦值,交換(swap)(與另外一個unique_lock對象交換他們所管理的Mutex對象的所有權),釋放(release)(返回指向它所管理的Mutex對象的指針).
    (3)獲取屬性操作:owns_lock(返回當前unique_lock對象是否獲得了鎖),operator bool()(與owns_lock功能相同,返回當前unique_lock對象是否獲得了鎖,mutex(返回當前unique_lock對象所管理的Mutex對象的指針).

unique_lock::lock

該函數返回時,當前的unique_lock對象便擁有了它所管理的Mutex對象的鎖,如果上鎖失敗,則拋出system_error異常.

unique_lock::try_lock

上鎖操作,調用它所管理的Mutex對象的try_lock函數,如果上鎖成功,返回true,否則返回false.

std::unique_lock::try_lock_for

上鎖操作,調用它所管理的Mutex對象的try_lock_for函數,上鎖成功,返回true,否則返回false.

std::unique_lock::release

返回指向所管理的Mutex對象的指針,並釋放所有權.

std::unique_lock::owns_lock

返回當前std::unique_lock對象是否獲得了鎖.

頭文件介紹

  • Provides類:std::promise,std::package_task
  • Futures類:std::future,shared_future.
  • Provides函數:std::async()
  • 其他類型:std::future_error,std::future_errc,std::future_status,std::launch.

std::promise類介紹

  • promise對象可以保存某一類型T的值,該值可以被future對象讀取(可能在另外一個線程中),因此promise也提供了一種線程同步的手段,在promise對象構造時可以和一個共享狀態(通常是std::future)相關聯,並可一在相關聯的共享狀態(std::future)上保存一個類型爲T的值.
  • 可以通過get_future來獲取與該promise對象相關聯的future對象,調用該函數之後,兩個對象共享相同的共享狀態.
  • promise對象是異步Provider,它可以在某一時刻設置共享狀態的值.
  • future對象可以異步返回共享狀態的值,或者在必要的情況下阻塞調用者並等待共享狀態標誌爲ready,然後才能獲取共享狀態的值 .

std::promise構造函數

  • default(1) promise();
  • with allocator(2) template promise(allocator_arg_t aa,const Alloc& alloc);
  • copy deleted promise(const promise&)=delete;
  • move(4) promise(promise&& x) noexcept;
    (1)默認構造函數,初始化一個空的共享狀態,
    (2)帶自定義內存分配器的構造函數,與默認構造函數類似,使用自定義分配器來分配共享狀態
    (3)拷貝構造函數,被禁用.
    (4)移動構造函數.

std::promise::get_future介紹

  • 該函數返回一個與promise共享狀態相關聯的future,返回的future對象可以訪問由promise對象設置在共享狀態上的值或者某個異常對象,只能從promise共享狀態獲取一個future對象,在調用該函數之後,promise對象通常會在某個時間點準備好(設置一個值或者一個異常對象),如果不設置值或異常,promise對象在析構時會自動設置一個future_error異常.
  • std::promise::set_value介紹
    generic template(1) void set_value(const T& val); void set_value(T&& val);
    specializations(2) void promise

std::promise::set_value_at_thread_exit 介紹

*設置共享狀態的值,但是不將共享狀態的標誌設置爲 ready,當線程退出時該 promise 對象會自動設置爲 ready。如果某個 std::future 對象與該 promise 對象的共享狀態相關聯,並且該 future 正在調用 get,則調用 get 的線程會被阻塞,當線程退出時,調用 future::get 的線程解除阻塞,同時 get 返回 set_value_at_thread_exit 所設置的值。注意,該函數已經設置了 promise 共享狀態的值,如果在線程結束之前有其他設置或者修改共享狀態的值的操作,則會拋出 future_error( promise_already_satisfied )。

std::promise::swap介紹

交換promise的共享狀態.

std::package_task

  • std::packaged_task**包裝一個可調用的對象**,並且允許異步獲取該可調用對象產生的結果,從包裝可調用對象意義上來講,std::package_task與std::function類似,只不過std::packaged_task將其包裝的可調用對象的執行結果傳遞給一個std::future對象(該對象通常在另外一個線程中獲取std::packaged_task任務的執行結果).
  • std::packaged_task對象內部包含兩個最基本元素,一.被包裝的任務,任務是一個可調用的對象,如函數指針,成員函數指針或函數對象,二.共享狀態(shared state),用於保存任務的返回值,可以通過std::future對象來達到異步訪問共享狀態的效果.
  • 可以通過std::packsged_task::get_future來獲取與共享狀態相關聯的std::future對象,在調用該函數之後,兩個對象共享相同的共享狀態:
  • std::packaged_task對象是異步Provider,它是某一時刻通過調用被包裝的任務來設置共享狀態的值.
  • std::future對象是一個異步返回對象,通過它可以獲得共享狀態的值,當然在必要的時候需要等待共享狀態變爲ready;
  • std::packaged_task的共享狀態的生命週期一直持續到最後一個與之關聯的對象被釋放或者銷燬爲止.

std::packaged_task 構造函數

default(1) package_task() noexcept;
initialization(2) template explicit packaged_task (Fn &&fn);
with allocator(3) template

std::packaged_task::valid 介紹

檢查當前packaged_task是否和一個有效的共享狀態相關聯,對於由默認構造函數生成的package_task對象,該函數返回false,除非中間進行了move賦值操作或者swap操作.

std::packaged_task::operator()(Args…..args)介紹

  • 調用該packaged_task對象所包裝的對象(通常爲函數指針,函數對象,lambda表達式等),傳入的參數爲args,調用該函數一般會發生兩種情況:
  • 如果成功調用packaged_task所包裝的對象,則返回值(如果包裝的對象有返回值的話)被保存在packaged_task的共享狀態中.
  • 如果調用package_task所包裝的對象失敗,並且拋出了異常,則異常也會被保存在packaged_task的共享狀態中,調用失敗,並且拋出了異常,則異常也會被保存在package_task的共享狀態中.

std::packaged_task::make_ready_at_thread_exit 介紹

  • 該函數會調用被包裝的任務,並向任務傳遞參數,類似 std::packaged_task 的 operator() 成員函數。但是與 operator() 函數不同的是,make_ready_at_thread_exit 並不會立即設置共享狀態的標誌爲 ready,而是在線程退出時設置共享狀態的標誌。
  • 如果與該 packaged_task 共享狀態相關聯的 future 對象在 future::get 處等待,則當前的 future::get 調用會被阻塞,直到線程退出。而一旦線程退出,future::get 調用繼續執行,或者拋出異常。

std::package_task::reset()介紹

重置packaged_task的共享狀態,但是保留之前的被包裝的任務.使得packaged_task 對象被重用.

std::packaged_task::swap() 介紹

交換 packaged_task 的共享狀態。

future介紹

  • std::future可以用來獲取異步任務的結果,因此可以把它當成一種簡單的線程間同步的手段. future通常由某個Provider創建,我們可以把Provider想象成一個異步任務的提供者,Provider在某個線程中設置共享狀態的值,與該共享狀態相關聯的future對象調用get(通常在另一個線程中)獲取該值,如果當前的共享狀態部位ready,則std::future::get會阻塞當前的調用線程.直到Provider設置了當前共享狀態的值,get方法返回異步任務的值或異常.
  • 一個有效的std::future對象通常由以下三種Provider創建,並和某個共享狀態相關聯,Provider可以是函數,也可以是類:
  • std::async()函數.
  • std::promise::get_future,此時get_future爲promise類的成員函數.
  • std::packaged_task,此時get_future爲package_task類的成員函數.
  • 一個 std::future 對象只有在有效(valid)的情況下才有用(useful),由 std::future 默認構造函數創建的 future 對象不是有效的(除非當前非有效的 future 對象被 move 賦值另一個有效的 future 對象)。

std::future構造函數

  • std::future一般由std::async,std::promise::get_future,std::packaed_task::get_future創建,不過也提供了構造函數:
  • default(1) future() noexcept;
  • copydeleted future(const future&)=delete;
  • move(3) future(future&& y)noexcept;
std::future<int> fut;   //默認構造函數  
fut=std::async(do_some_task);

std::future::share()

返回一個std::shared_future對象(本文後續內容將介紹std::shared_future);調用該函數之後,該std::future對象本身已經不和任何共享狀態相關聯,因此該std::future的狀態不再是valid的了.

std::future::get()

std::future::get一共有三種形式:
(1) generic template(1) T get(); 返回一個值.
(2) reference specialization R& future

std::future::valid()

  • 檢查當前的std::future對象是否有效,即釋放與某個共享狀態相關聯,一個有效的std::future對象只能通過std::async(),std::promise::get_future或者std::packaged_task::get_future來初始化.由std::future默認構造函數創建的std::future對象是無效的,通std::future的move賦值後該std::future對象也可以變爲valid.

std::future::wait()

  • 等待與當前std::future對象相關聯的共享狀態的標誌變爲ready;
  • 如果共享狀態的標誌不是ready(此時Provider沒有在共享狀態上設置值或者異常),調用該函數會被阻塞當前線程,直到共享狀態的標誌變爲ready,一旦共享狀態變爲ready,wait()函數返回,當前線程被解除阻塞,但是wait()並不讀取共享狀態的值或者異常;

std::future::wait_for()

與std::future::wait()的功能類似,即等待與該std::future對象相關聯的共享狀態變爲ready,該函數的原型如下:

template<class Rep,class Period> future_status wait_for(const chrono::duration<Rep,Period>& rel_time)const;  

而與std::future::wait()不同的是,wait_for()可以設置一個時間段rel_time,如果共享的標誌在該時間段結束之前沒有被Provider設置爲ready,則調用wait_for的線程被阻塞,在等待了rel_time的時間長度後wait_until()返回.
* future_status::ready:共享的狀態已經變爲ready,即Provider在共享狀態上設置了值或異常.
* future_status::timeout:超時,即在規定的時間內共享狀態的標誌沒有變爲ready.
* future_status::deffered:共享狀態包含一個deferred函數.

std::future::wait_until()

wait_until()可以設置一個系統絕對時間,如果共享狀態的標誌在該時間點到來之前沒有被Provider設置爲ready,則調用wait_until的線程阻塞. ### std::shared_future介紹
std::sahred_future與std::future類似但是std::shared_future可以拷貝,多個std::shared_future可以共享某個共享狀態的最終結果(即共享狀態的某個值或者異常),shared_future可以通過某個std::future對象隱式轉換(std::shared_future的構造函數 ),或者通過future::shared()顯式轉換,無論哪種轉換,被轉換的那個std::future對象都會變爲not-valid.

std::shared_future構造函數.

(1) default(1) shared_future() noexcept;
(2)copy(2) shared_future(const shared_future& x);
(3)move(3) shared_future(shared_future&& x)noexcept;
(4)move from future(4) shared_future(future&& x) noexcept;
最後move form future(4) 即從一個有效的std::future對象構造一個std::shared_future,構造之後std::future對象x變爲無效.

std::async()介紹

(1) unspecified policy(1) template

與std::future相關的枚舉類介紹

  • enum class future_errc;
  • enum class future_status;
  • enum calss launch;
    future_errc類不長用,

std::launch類型

  • launch::async:異步任務會在另外一個線程中調用,並通過共享狀態返回異步任務的結果.

條件變量頭文件裏的類和函數介紹.

頭文件主要包含了與條件變量相關的類和函數,相關的類包括std::condition_variable和std::condition_variable_any,還有枚舉類型std::cv_status,另外還包括函數std::notify_all_thread_exit(),下面介紹以上幾種類型.

condition_variable類介紹

  • std::condition_variable是條件變量,Linux下使用Pthread庫中的pthread_cond_*()函數提供了與條件變量相關的功能.
  • 當std::condition_variable對象的某個wait函數被調用的時候,它使用std::unique_lock(通過std::mutex)來鎖住當前線程,當前線程會一直被阻塞,直到另外一個線程在相同的std::condition_variable對象上調用了notification函數來喚醒當前線程.
  • std::condition_variable對象通常使用std::unique_lock來等待,如果需要使用另外的lockable類型,可以使用std::condition_variable_any類.

std::condition_variable構造函數

default(1) condtion_variable();
copydeleted condition_variable(const condition_variable&)=delete;
condition_variable的拷貝構造函數被禁用,只提供了默認構造函數.

std::condition_variable::wait()介紹

  • (絕對的)uncondition(1) void wait(unique_lock& lck);
  • predicate(2) template void wait(unique_lock& lck,Predicate pred);
  • std::condition_variable提供了兩種wait()函數,當前線程調用wait()後將被阻塞(此時當前線程應該獲得了鎖(mutex)),不妨設獲得鎖lck,直到另外某個線程調用notify_*喚醒當前線程.
  • 在線程被阻塞時,該函數會自動調用lck.unlock()釋放鎖,使得其他被阻塞在鎖競爭上的線程得以繼續執行,另外,一旦當前線程獲得通知(notified,通常是另外某個線程調用notify_*喚醒當前線程),wait()函數也是自動調用lck.lock(),使得lck的狀態和wait函數被調用時相同.
  • 在第二種情況下(即設置了Predicate),只有當pred條件爲fasle時調用wait()纔會阻塞當前線程,並且在收到其他線程的通知後只有當pred爲true時纔會被解除阻塞,因此第二種情況類似以下代碼.
    while(!pred()) wait(lck);

std::condition_variable::wait_for()介紹

與std::condition_variable::wait()類似,不過wait_for可以指定一個時間段,在當前線程收到通知或者指定的時間rel_time超時之前,該線程都會處於阻塞狀態,而一旦超時或者收到裏其他線程的通知,wait_for返回,剩下的處理步驟和wait()類似.

std::condition_variable::wait_until()介紹

與wait_for()類似,不過wait_until可以指定一個時間點.

std::condition_variable::notify_one()介紹

喚醒某個等待線程,如果當前沒有等待線程,則該函數什麼也不做,如果同時存在多個等待線程,則喚醒某個線程是不確定的.

std::condition_variable::notify_all()介紹

喚醒所有等待的線程,如果沒有等待的線程,則不做什麼.

std::condition_variable_any 介紹

與std::condition_variable類似,只不過std::condition_variable_any的wait函數可以接受任何lockable參數.而std::condition_variable只能接受std::unique_lock類型的參數

cv_status枚舉類型介紹

  • cv_status::no_timeout wait_for或者wait_until沒有超時,即在規定的時間內線程接受到通知.
  • cv_status::timeout wait_for或者wait_until超時.

notify_all_at_thread_exit .

void notify_all_at_thread_exit(condition_variable& cond,unique_lock<mutex> lck);  
當調用該函數的線程退出時,所有在cond條件變量上等待的線程都會收到通知.  

atomic類型詳解–atomic_flag介紹

  • 頭文件中最簡單的原子類型:atomic_flag,atomic_flag一種簡單的原子布爾類型,只支持兩種操作,test-and-set和clear.

std::atomic_flag構造函數

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

  • std::atomic_flag只有默認構造函數,拷貝構造函數已被禁用,因此不能從其他std::atomic_flag對象構造一個新的std::atomic_flag對象.
  • 如果在初始化時沒有明確使用ATOMIC_FLAG_INIT初始化,那麼新創建的std::atomic_flag對象的狀態是未指定的(既沒有被set也沒有被clear),另外,atomic_flag不能被拷貝,也不能move賦值.
  • ATOMIC_FLAG_INIT:如果某個std::atomic_flag對象使用該宏初始化,那麼可以保證該std::atomic_flag對象在創建時處於clear狀態.

atomic_flag::test_and_set 介紹

函數原型:

bool test_and_set(memory_order sync = memory_order_seq_cst)
volatile noexcept;
bool test_and_set(memory_order sync=memory_order_seq_cst); 
  • test_and_set()函數檢查std::atomic_flag標誌,如果std::atomic_flag之前沒有被設置過,則設置std::atomic_flag的標誌,並返回先前該std::atomic_flag對象是否被設置過.如果已經被設置過,則返回true,否則返回false.

test_and_set參數sync的取值.

Memory Order值 Memory Order類型
memory_order_relaxed Relaxed
memory_order_consume Consume
memory_order_acquire Acquire
memeory_order_release Release
memory_order_acq_rel Acquire/Release
memory_order_seq_cst Sequentially consistent

std::atomic_flag::clear()介紹

清除std::atomic_flag對象的標誌位,即設置atomic_flag的值爲false,clear函數的原型如下:

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

清除std::atomic_flag標誌使得下一次調用std::atomic_flag::test_and_set返回false;

std::atomic介紹

std::atomic是模板類,一個模板類型爲T的原子對象中封裝了一個類型爲T的值.

template<class T> struct
 atomic;  

原子類型對象的主要特點就是從不同線程訪問不會導致數據競爭. 因此從不同線程訪問某個原子對象是良性行爲,而通常對於非原子類型而言,併發的訪問某個對象(如果不做任何同步操作)會導致未定義的行爲發生. std::atomic成員函數

std::atmoic的構造函數如下:

default(1) atmoic() noexcept=default;
initialization(2) constexpr atomic(T val) noexcept;
copydeleted atomic(const atomic&)=delete;
1.默認構造函數,由默認構造函數創建的std::atomic對象處於未初始化狀態,對於爲初始化的std::atomic對象可以由atomic_init函數進行初始化.
2.初始化構造函數,由類型T初始化一個std::atomic對象.
3.拷貝構造函數被禁用.
std::atomic::operator=()函數
std::atomic的賦值操作函數定義如下:
set value(1) T operator=(T val) noexcept;
T operator=(T val)volatile noexcept;
copydeleted;
普通的賦值拷貝操作已經被禁用,但是一個類型爲T的變量可以賦值給相應的原子類型變量(相當於隱式轉換),該操作是原子的,內存序默認順序一致性(memory_order_seq_cst),如果需要指定其他的內存序,需要使用std::atomic::store();

is_lock_free


bool is_lock_free() const volatile noexcept;
bool is_lock_free() const noexcept;
判斷std::atomic對象是否具備lock-free的特性,如果某個對象滿足lock-free特性,在多個線程訪問該對象時不會導致線程阻塞,

store

函數原型:

void store(T val,memory_order sync = memory_order_seq_cst) volatile noexcept;  
void store(T val,memory_order sync = memory_order_seq_cst) noexcept;   修改被封裝的值,std::atomic::store函數將類型爲T的參數val複製給原子對象所封裝的值,T是std::atomic類模板參數,另外參數sync指定內存序.  
Memory Order 值 Memory Order類型
memory_order_relaxed Relaxed
memory_order_release Release
memory_order_seq_cst Sequentially consistent

load

T load(memory_order sync=memory_order_seq_cst) const volatile  noexcept;
T load(memory_order sync=memory_order_seq_cst) cosnt noexcept;
operatorT() const volatile noexcept;
operator T()const noexcept; 

與load功能類似,也是讀取被封裝的值,operator T()是類型轉換操作,默認的內存序是std::memory_order_seq_cst,如果需要指定其他的內存序,應該使用load()函數;
exchange

T exchange(T val,memory_order sync = memory_order_seq_cst) volatile noexcept;
T exchange(T val,memory_order_sync = memory_order sync =memory_order_seq_cst) noexcept;
讀取並修改被封裝的值,exchange會將val指定的值替換掉之前該原子對象封裝的值,並返回之前該原子對象封裝的值,整個過程是原子的.

內存序(簡單介紹一下,前面用到了,知道內存序是爲了約束內存操作的就行,具體的內存模型以後再學習)

c++11中中定義了以下6種語義來對內存操作的行爲進行約束,這些語義分別規定了不同的內存操作在其他線程中的可見性問題.

enum memory_oeder{
memory_order_relaxed, //保證是原子操作,但是不保證優化後的代碼順序.
memory_order_consume, //與操作數相關的纔會有效.
memory_order_acquire, //不僅是從內存讀,還保證了內存代碼執行的順序,這句代碼必須在這句代碼後面的代碼執行前執行.
memory_order_release, //確保寫入內存,但同時也保證了:這句代碼必須在執行完這句代碼前面的代碼之後執行.
memory_order_acq_rel, //看一下exchange吧,相當於acquire和release;
memory_order_seq_cst //不允許編譯器調整語句順序,
};

發佈了109 篇原創文章 · 獲贊 238 · 訪問量 37萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章