1. 程式人生 > >C++筆記-並發編程 異步任務(async)

C++筆記-並發編程 異步任務(async)

賦值 死鎖 ber incr 函數模板 lag div 超時值 bre

轉自 https://www.cnblogs.com/diysoul/p/5937075.html

參考:https://zh.cppreference.com/w/cpp/thread/lock_guard

創建 lock_guard 對象時,它試圖接收給定互斥的所有權。控制離開創建 lock_guard 對象的作用域時,銷毀 lock_guard 並釋放互斥。

lock_guard 類不可復制。

模板形參

Mutex - 要鎖定的互斥。類型必須滿足基礎可鎖 (BasicLockable) 要求

成員類型

成員類型 定義
mutex_type
Mutex

成員函數

(構造函數) 構造 lock_guard ,可選地鎖定給定的互斥
(公開成員函數)
(析構函數) 析構 lock_guard 對象,解鎖底層互斥
(公開成員函數)
operator= [被刪除] 不可復制賦值
(公開成員函數)

示例

運行此代碼
#include <thread>
#include <mutex>
#include <iostream>
 
int
g_i = 0; std::mutex g_i_mutex; // 保護 g_i void safe_increment() { std::lock_guard<std::mutex> lock(g_i_mutex); ++g_i; std::cout << std::this_thread::get_id() << ": " << g_i << \n; // g_i_mutex 在鎖離開作用域時自動釋放 } int main() { std::cout
<< "main: " << g_i << \n; std::thread t1(safe_increment); std::thread t2(safe_increment); t1.join(); t2.join(); std::cout << "main: " << g_i << \n; }

可能的輸出:

main: 0
140641306900224: 1
140641298507520: 2
main: 2

C++並發編程 異步任務(async)

線程基本的互斥和同步工具類, 主要包括:
  std::mutex 類
  std::recursive_mutex 類
  std::timed_mutex 類
  std::recursive_timed_mutex 類
  std::lock_guard 類型模板
  std::unique_lock 類型模板
  std::lock 函數模板
  std::once_flag 類
  std::call_once 函數模板

std::mutex 類

  std::mutex 上鎖須要調用 lock() 或 try_lock(), 當有一個線程獲取了鎖, 其它線程想要取得此對象的鎖時, 會被阻塞(lock)或失敗(try_lock). 當線程完成共享數據的保護後, 需要調用 unlock 進行釋放鎖.
  std::mutex 不支嵌套, 如果兩次調用 lock, 會產生未定義行為.

std::recursive_mutex 類

使用方法同 std::mutex, 但 std::recursive_mutex 支持一個線程獲取同一個互斥量多次,而沒有對其進行一次釋放. 但是同一個線程內, lock 與 unlock 次數要相等, 否則其它線程將不能取得任何機會.
其原理是, 調用 lock 時, 當調用線程已持有鎖時, 計數加1; 調用 try_lock 時, 嘗試取得鎖, 失敗時不會阻塞, 成功時計數加1; 調用 unlock 時, 計數減1, 如果是最後一個鎖時, 釋放鎖.
需要註意的是: 調用 try_lock時, 如果當前線程未取得鎖, 即使沒有別的線程取得鎖, 也有可能失敗.

std::timed_mutex 類

std::timed_mutex 在 std::mutex 的基礎上支持讓鎖超時. 上鎖時可以調用 try_lock_for, try_lock_until 設置超時值.
try_lock_for 的參數是需要等待的時間, 當參數小於等於0時會立即返回, 效果和使用 try_lock 一樣.
try_lock_until 傳入的參數不能小於當前時間, 否則會立即返回, 效果和使用 try_lock 一樣. 實際上 try_lock_for 內部也是調用 try_lock_until 實現的.
tm.try_lock_for(std::chrono::milliseconds(1000)) 與 tm.try_lock_until(std::chrono::steady_clock::now() + std::chrono::milliseconds(1000)) 等價, 都是等待1s.

std::recursive_timed_mutex 類

std::recursive_timed_mutex 在 std::recursive_mutex 的基礎上, 讓鎖支持超時.
用法同 std::timed_mutex, 超時原理同 std::recursive_mutex.

std::lock_guard 類型模板

std::lock_guard 類型模板為基礎鎖包裝所有權. 指定的互斥量在構造函數中上鎖, 在析構函數中解鎖.
這就為互斥量鎖部分代碼提供了一個簡單的方式: 當程序運行完成時, 阻塞解除, 互斥量解鎖(無論是執行到最後, 還是通過控制流語句break或return, 亦或是拋出異常).
std::lock_guard 不支持拷貝構造, 拷貝賦值和移動構造.

std::unique_lock 類型模板

std::unique_lock 類型模板比 std::loc_guard 提供了更通用的所有權包裝器.
std::unique_lock 可以調用 unlock 釋放鎖, 而後當再次需要對共享數據進行訪問時再調用 lock(), 但是必須註意一次 lock 對應一次 unlock, 不能連續多次調用同一個 lock 或 unlock.
std::unique_lock 不支持拷貝構造和拷貝賦值, 但是支持移動構造和移動賦值.
std::unique_lock 比 std::loc_guard 還增加了另外幾種構造方式:
unique_lock(_Mutex& _Mtx, adopt_lock_t) 構建持有鎖實例, 其不會調用 lock 或 try_lock, 但析構時默認會調用 unlock.
unique_lock(_Mutex& _Mtx, defer_lock_t) 構建非持有鎖實例, 其不會調用 lock 或 try_lock, 如果沒有使用 std::lock 等函數修改標誌, 析構時也不會調用 unlock.
unique_lock(_Mutex& _Mtx, try_to_lock_t) 嘗試從互斥量上獲取鎖, 通過調用 try_lock
unique_lock(_Mutex& _Mtx, const chrono::duration<_Rep, _Period>& _Rel_time) 在給定時間長度內嘗試獲取鎖
unique_lock(_Mutex& _Mtx, const chrono::time_point<_Clock, _Duration>& _Abs_time) 在給定時間點內嘗試獲取鎖
bool owns_lock() const 檢查是否擁有一個互斥量上的鎖

std::lock 函數模板

std::lock 函數模板提供同時鎖住多個互斥量的功能, 且不會有因改變鎖的一致性而導致的死鎖. 其聲明如下:
template<typename LockableType1,typename... LockableType2> void lock(LockableType1& m1,LockableType2& m2...);

C++筆記-並發編程 異步任務(async)