std::scoped_lock
來自 cppreference.com
定義於標頭檔案 <mutex> |
||
template< class... MutexTypes > class scoped_lock; |
(C++17 起) | |
scoped_lock
類是一個互斥體包裝器,它提供了一種方便的 RAII 風格機制,用於在作用域塊的持續時間內擁有零個或多個互斥體。
當建立 scoped_lock
物件時,它會嘗試獲取它所給定的互斥體的所有權。當控制離開建立 scoped_lock
物件的範圍時,scoped_lock
會被銷燬,並且互斥體會被釋放。如果給定多個互斥體,則會使用死鎖避免演算法,如同透過 std::lock。
scoped_lock
類不可複製。
目錄 |
[編輯] 模板引數
MutexTypes | - | 要鎖定的互斥體型別。除非 sizeof...(MutexTypes) == 1,否則型別必須滿足 Lockable 要求,在這種情況下,唯一的型別必須滿足 BasicLockable |
[編輯] 成員型別
成員型別 | 定義 |
mutex_type (有條件存在) |
如果 sizeof...(MutexTypes) == 1,成員型別 |
[編輯] 成員函式
構造一個 scoped_lock ,可選地鎖定給定的互斥體(public member function) | |
銷燬 scoped_lock 物件,解鎖底層互斥體(public member function) | |
operator= [已刪除] |
不可複製賦值 (public member function) |
[編輯] 注意
一個常見的初學者錯誤是“忘記”給 scoped_lock
變數命名,例如 std::scoped_lock(mtx);(這會預設構造一個名為 mtx
的 scoped_lock
變數)或 std::scoped_lock{mtx};(這會構造一個立即銷燬的純右值物件),從而實際上沒有構造一個在作用域的其餘部分持有互斥體的鎖。
特性測試宏 | 值 | 標準 | 特性 |
---|---|---|---|
__cpp_lib_scoped_lock |
201703L |
(C++17) | std::scoped_lock
|
[編輯] 示例
以下示例使用 std::scoped_lock
以 RAII 風格鎖定一對互斥體,避免死鎖。
執行此程式碼
#include <chrono> #include <functional> #include <iostream> #include <mutex> #include <string> #include <thread> #include <vector> using namespace std::chrono_literals; struct Employee { std::vector<std::string> lunch_partners; std::string id; std::mutex m; Employee(std::string id) : id(id) {} std::string partners() const { std::string ret = "Employee " + id + " has lunch partners: "; for (int count{}; const auto& partner : lunch_partners) ret += (count++ ? ", " : "") + partner; return ret; } }; void send_mail(Employee&, Employee&) { // Simulate a time-consuming messaging operation std::this_thread::sleep_for(1s); } void assign_lunch_partner(Employee& e1, Employee& e2) { static std::mutex io_mutex; { std::lock_guard<std::mutex> lk(io_mutex); std::cout << e1.id << " and " << e2.id << " are waiting for locks" << std::endl; } { // Use std::scoped_lock to acquire two locks without worrying about // other calls to assign_lunch_partner deadlocking us // and it also provides a convenient RAII-style mechanism std::scoped_lock lock(e1.m, e2.m); // Equivalent code 1 (using std::lock and std::lock_guard) // std::lock(e1.m, e2.m); // std::lock_guard<std::mutex> lk1(e1.m, std::adopt_lock); // std::lock_guard<std::mutex> lk2(e2.m, std::adopt_lock); // Equivalent code 2 (if unique_locks are needed, e.g. for condition variables) // std::unique_lock<std::mutex> lk1(e1.m, std::defer_lock); // std::unique_lock<std::mutex> lk2(e2.m, std::defer_lock); // std::lock(lk1, lk2); { std::lock_guard<std::mutex> lk(io_mutex); std::cout << e1.id << " and " << e2.id << " got locks" << std::endl; } e1.lunch_partners.push_back(e2.id); e2.lunch_partners.push_back(e1.id); } send_mail(e1, e2); send_mail(e2, e1); } int main() { Employee alice("Alice"), bob("Bob"), christina("Christina"), dave("Dave"); // Assign in parallel threads because mailing users about lunch assignments // takes a long time std::vector<std::thread> threads; threads.emplace_back(assign_lunch_partner, std::ref(alice), std::ref(bob)); threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(bob)); threads.emplace_back(assign_lunch_partner, std::ref(christina), std::ref(alice)); threads.emplace_back(assign_lunch_partner, std::ref(dave), std::ref(bob)); for (auto& thread : threads) thread.join(); std::cout << alice.partners() << '\n' << bob.partners() << '\n' << christina.partners() << '\n' << dave.partners() << '\n'; }
可能的輸出
Alice and Bob are waiting for locks Alice and Bob got locks Christina and Bob are waiting for locks Christina and Alice are waiting for locks Dave and Bob are waiting for locks Dave and Bob got locks Christina and Alice got locks Christina and Bob got locks Employee Alice has lunch partners: Bob, Christina Employee Bob has lunch partners: Alice, Dave, Christina Employee Christina has lunch partners: Alice, Bob Employee Dave has lunch partners: Bob
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
LWG 2981 | C++17 | 提供了冗餘的 scoped_lock<MutexTypes...> 推導指南 |
已移除 |
[編輯] 另請參閱
(C++11) |
實現可移動的互斥體所有權包裝器 (類模板) |
(C++11) |
實現嚴格基於作用域的互斥體所有權包裝器 (類模板) |