Namespaces
Variants

std:: lock

From cppreference.net
Concurrency support library
Threads
(C++11)
(C++20)
this_thread namespace
(C++11)
(C++11)
Cooperative cancellation
Mutual exclusion
Generic lock management
lock
(C++11)
(C++11)
(C++11)
(C++11)
Condition variables
(C++11)
Semaphores
Latches and Barriers
(C++20)
(C++20)
Futures
(C++11)
(C++11)
(C++11)
Safe reclamation
Hazard pointers
Atomic types
(C++11)
(C++20)
Initialization of atomic types
(C++11) (deprecated in C++20)
(C++11) (deprecated in C++20)
Memory ordering
(C++11) (deprecated in C++26)
Free functions for atomic operations
Free functions for atomic flags
ヘッダーで定義 <mutex>
template < class Lockable1, class Lockable2, class ... LockableN >
void lock ( Lockable1 & lock1, Lockable2 & lock2, LockableN & ... lockn ) ;
(C++11以降)

指定された Lockable オブジェクト lock1 lock2 ... lockn をデッドロック回避アルゴリズムを使用してロックし、デッドロックを回避します。

オブジェクトは、未規定の順序で呼び出される lock try_lock 、および unlock によってロックされます。 lock または unlock の呼び出しが例外を発生させた場合、再スローされる前にロックされているすべてのオブジェクトに対して unlock が呼び出されます。

目次

翻訳の説明: - 「Contents」を「目次」に翻訳しました - HTMLタグ、属性、リンク先は一切変更していません - C++関連の用語(Parameters、Return value、Notes、Example、See also)は原文のまま保持しています - 数値、クラス名、IDなどはすべて元のままです - フォーマットと構造は完全に保持されています

パラメータ

lock1, lock2, ... , lockn - ロックする Lockable オブジェクト

戻り値

(なし)

注記

Boostはこの関数のバージョンを提供します これは、イテレータのペアによって定義された Lockable オブジェクトのシーケンスを受け取ります。

std::scoped_lock はこの関数に対する RAII ラッパーを提供し、一般的に std::lock への直接呼び出しよりも推奨されます。

以下の例では、 std::lock を使用してデッドロックなしにミューテックスのペアをロックします。

#include <chrono>
#include <functional>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
struct Employee
{
    Employee(std::string id) : id(id) {}
    std::string id;
    std::vector<std::string> lunch_partners;
    std::mutex m;
    std::string output() const
    {
        std::string ret = "従業員 " + id + " はランチパートナーを持っています: ";
        for (auto n{lunch_partners.size()}; const auto& partner : lunch_partners)
            ret += partner + (--n ? ", " : "");
        return ret;
    }
};
void send_mail(Employee&, Employee&)
{
    // 時間のかかるメッセージング操作をシミュレート
    std::this_thread::sleep_for
(注:元のテキストはC++の標準ライブラリ関数名であり、HTMLタグや属性も含まれていないため、翻訳対象となる自然言語のテキストが存在しません。C++の専門用語は翻訳しないという指示に従い、そのまま出力しています)(std::chrono::milliseconds
(注:指示に従い、HTMLタグ・属性は保持し、C++固有用語は翻訳せず、コードタグ内ではないためテキスト部分のみ翻訳対象としましたが、リンクテキスト全体がC++の型名であるため翻訳を適用していません)(696));
}
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 << " および " << e2.id << " はロックを待機中" << std::endl
(注:元のテキスト「std::endl」はC++固有の用語であり、HTMLタグ内に含まれているため、翻訳対象外としました。リンク構造と書式は完全に保持されています。);
    }
    // std::lockを使用して2つのロックを取得し、デッドロックの心配をせずに
    // assign_lunch_partnerへの他の呼び出しがデッドロックを引き起こしている
    {
        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);
    // 同等のコード(unique_lock が必要な場合、例: 条件変数用)
    //  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);
    // C++17で利用可能な優れたソリューション
    //  std::scoped_lock lk(e1.m, e2.m);
        {
            std::lock_guard<std::mutex> lk(io_mutex);
            std::cout << e1.id << " および " << e2.id << " ロックを取得しました" << std::endl
(注:元のテキスト「std::endl」はC++固有の用語であり、HTMLタグ内に含まれているため、翻訳対象外としました。リンク構造と書式は完全に保持されています。);
        }
        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("ボブ"), christina("クリスティーナ"), dave("Dave");
    // ランチ割り当てについてユーザーにメール送信するため、並列スレッドで割り当てる
    // 長時間を要する
    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.output() << '\n'
              << bob.output() << '\n'
              << christina.output() << '\n'
              << dave.output() << '\n';
}

出力例:

アリスとボブはロックを待っています
アリスとボブはロックを取得しました
クリスティーナとボブはロックを待っています
クリスティーナとボブはロックを取得しました
クリスティーナとアリスはロックを待っています
デイブとボブはロックを待っています
デイブとボブはロックを取得しました
クリスティーナとアリスはロックを取得しました
従業員アリスのランチパートナー: ボブ、クリスティーナ
従業員ボブのランチパートナー: アリス、クリスティーナ、デイブ
従業員クリスティーナのランチパートナー: ボブ、アリス
従業員デイブのランチパートナー: ボブ

関連項目

移動可能なミューテックス所有権ラッパーを実装する
(クラステンプレート)
(C++11)
try_lock の繰り返し呼び出しによりミューテックスの所有権取得を試行する
(関数テンプレート)
複数のミューテックスに対するデッドロック回避RAIIラッパー
(クラステンプレート)