thread_lock

thread_lock (여러 Lockable 객체를 교착 상태 없이 잠그는 함수)

이 페이지에서는 std::lock 함수 템플릿에 대해 설명해요. std::lock은 여러 Lockable 객체를 교착 상태(deadlock)를 피하면서 잠그는 함수예요. 이 함수는 지정된 객체들을 잠그기 위해 내부적으로 lock, try_lock, unlock을 적절히 호출해요.

출처: cppreference

본문

정의

헤더 <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이 호출돼요.

매개변수

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 = "Employee " + id + " has lunch partners: ";
        for (auto n{lunch_partners.size()}; const auto& partner : lunch_partners)
            ret += partner + (--n ? ", " : "");
        return ret;
    }
};

void send_mail(Employee&, Employee&)
{
    // Simulate a time-consuming messaging operation
    std::this_thread::sleep_for(std::chrono::milliseconds(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 << " and " << e2.id << " are waiting for locks" << std::endl;
    }

    // Use std::lock to acquire two locks without worrying about 
    // other calls to assign_lunch_partner deadlocking us
    {
        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 (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);
    // Superior solution available in C++17
    //  std::scoped_lock lk(e1.m, e2.m);
        {
            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.output() << '\n'
              << bob.output() << '\n'
              << christina.output() << '\n'
              << dave.output() << '\n';
}

가능한 출력:

Alice and Bob are waiting for locks
Alice and Bob got locks
Christina and Bob are waiting for locks
Christina and Bob got 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
Employee Alice has lunch partners: Bob, Christina 
Employee Bob has lunch partners: Alice, Christina, Dave 
Employee Christina has lunch partners: Bob, Alice 
Employee Dave has lunch partners: Bob

같이 보기

unique_lock (C++11) 이동 가능한 뮤텍스 소유권 래퍼를 구현해요 (클래스 템플릿) [edit]
try_lock (C++11) try_lock을 반복 호출하여 뮤텍스 소유권을 얻으려 시도해요 (함수 템플릿) [edit]
scoped_lock (C++17) 여러 뮤텍스를 위한 교착 상태 회피 RAII 래퍼예요 (클래스 템플릿) [edit]

더 알아보기 (Learn more)

cppreference