名稱空間
變體
操作

std::scoped_lock

來自 cppreference.com
< cpp‎ | thread
 
 
併發支援庫
執行緒
(C++11)
(C++20)
this_thread 名稱空間
(C++11)
(C++11)
(C++11)
協同取消
互斥
(C++11)
通用鎖管理
(C++11)
(C++11)
scoped_lock
(C++17)
(C++11)
(C++11)
(C++11)
條件變數
(C++11)
訊號量
門閂和屏障
(C++20)
(C++20)
期值
(C++11)
(C++11)
(C++11)
(C++11)
安全回收
(C++26)
危險指標
原子型別
(C++11)
(C++20)
原子型別的初始化
(C++11)(C++20 中已棄用)
(C++11)(C++20 中已棄用)
記憶體排序
(C++11)(C++26 中已棄用)
原子操作的自由函式
原子標誌的自由函式
 
 
定義於標頭檔案 <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,成員型別 mutex_typeMutex 相同,即 MutexTypes... 中唯一的型別。否則,沒有成員 mutex_type

[編輯] 成員函式

構造一個 scoped_lock,可選地鎖定給定的互斥體
(public member function) [編輯]
銷燬 scoped_lock 物件,解鎖底層互斥體
(public member function) [編輯]
operator=
[已刪除]
不可複製賦值
(public member function) [編輯]

[編輯] 注意

一個常見的初學者錯誤是“忘記”給 scoped_lock 變數命名,例如 std::scoped_lock(mtx);(這會預設構造一個名為 mtxscoped_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...> 推導指南 已移除

[編輯] 另請參閱

實現可移動的互斥體所有權包裝器
(類模板) [編輯]
實現嚴格基於作用域的互斥體所有權包裝器
(類模板) [編輯]