std :: unique_lock <std :: mutex> 또는 std :: lock_guard <std :: mutex>?

두 가지 사용 사례가 있습니다.

A. 두 스레드의 액세스를 대기열에 동기화하고 싶습니다.

B. 두 스레드의 액세스를 큐에 동기화하고 스레드 중 하나가 다른 스레드에 의해 큐에 저장 될 내용을 기다리는 조건 변수를 사용하려고합니다.

사용 사례 AI의 경우를 사용하는 코드 예를 참조하십시오 std::lock_guard<>. 사용 사례 BI의 경우를 사용하는 코드 예를 참조하십시오 std::unique_lock<>.

둘 중 어느 것과 어떤 유스 케이스에서 사용해야하는지의 차이점은 무엇입니까?



답변

차이점은를 잠그고 잠금을 해제 할 수 있다는 것 std::unique_lock입니다. std::lock_guard건설시 한 번만 잠기고 파괴시 잠금이 해제됩니다.

따라서 유스 케이스 B의 경우 std::unique_lock조건 변수에 반드시 a가 필요 합니다. A의 경우 가드를 다시 잠글 지 여부에 따라 다릅니다.

std::unique_lock뮤텍스를 즉시 잠그지 않고 RAII 래퍼를 빌드하도록 구성 할 수있는 다른 기능이 있습니다 ( 여기 참조 ).

std::lock_guard또한 편리한 RAII 래퍼를 제공하지만 여러 뮤텍스를 안전하게 잠글 수는 없습니다. 제한된 범위에 대한 랩퍼가 필요할 때 사용할 수 있습니다 (예 : 멤버 함수).

class MyClass{
    std::mutex my_mutex;
    void member_foo() {
        std::lock_guard<mutex_type> lock(this->my_mutex);            
        /*
         block of code which needs mutual exclusion (e.g. open the same 
         file in multiple threads).
        */

        //mutex is automatically released when lock goes out of scope           
};

기본적으로 chmike으로 질문을 명확히하기 std::lock_guardstd::unique_lock동일합니다. 따라서 위의 경우로 대체 할 수 std::lock_guard있습니다 std::unique_lock. 그러나 std::unique_lock약간 더 많은 오버 헤드가있을 수 있습니다.

요즘에는 std::scoped_lock대신에 사용해야 합니다 std::lock_guard.


답변

lock_guard그리고 unique_lock거의 같은 것입니다; lock_guard인터페이스가 제한된 제한된 버전입니다.

A는 lock_guard항상 건축에서 파괴까지 잠금을 유지합니다. A unique_lock는 즉시 잠그지 않고 생성 할 수 있으며, 존재하는 어느 시점에서나 잠금 해제 할 수 있으며, 잠금 소유권을 한 인스턴스에서 다른 인스턴스로 이전 할 수 있습니다.

따라서 lock_guard의 기능이 필요하지 않으면 항상을 사용 하십시오 unique_lock. A가 condition_variable필요합니다 unique_lock.


답변

를 파괴하지 않고 사이 lock_guard에 수동으로 unlock뮤텍스 를 만들 수 있어야하는 경우가 아니면 사용하십시오 lock.

특히 condition_variable에 호출 할 때 절전 모드로 전환 할 때 뮤텍스를 잠금 해제합니다 wait. 이것이 lock_guard여기에서 충분하지 않은 이유 입니다.


답변

사이의 공통된 것들이있다 lock_guardunique_lock특정 차이.

그러나 질문의 ​​맥락에서 컴파일러는 lock_guard조건 변수와 함께 조합을 사용할 수 없습니다 . 스레드 호출이 조건 변수를 기다릴 때 뮤텍스가 자동으로 잠금 해제되고 다른 스레드 / 스레드가 통지하고 현재 스레드를 호출되면 (대기에서 나옴) 잠금이 다시 획득됩니다.

이 현상은의 원칙에 위배 lock_guard됩니다. lock_guard한 번만 구성하고 한 번만 파괴 할 수 있습니다.

따라서, lock_guard조건 변수와 함께 사용되지 않을 수 있지만,이 unique_lock(때문 될 수 unique_lock잠겨 수회 해제 할 수있다).


답변

그것들은 실제로 같은 뮤텍스가 아니며, lock_guard<muType>거의 동일하다 std::mutex. 수명이 스코프의 끝에서 끝나는 것 (D-tor)은이 두 뮤텍스에 대한 명확한 정의이다.

lock_guard<muType> 범위가 지정된 블록 동안 뮤텍스를 소유하는 메커니즘이 있습니다.

unique_lock<muType> 지연된 잠금, 잠금에 대한 시간 제약 된 시도, 재귀 잠금, 잠금 소유권 이전 및 조건 변수와 함께 사용할 수있는 래퍼입니다.

다음은 구현 예입니다.

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <chrono>

using namespace std::chrono;

class Product{

   public:

       Product(int data):mdata(data){
       }

       virtual~Product(){
       }

       bool isReady(){
       return flag;
       }

       void showData(){

        std::cout<<mdata<<std::endl;
       }

       void read(){

         std::this_thread::sleep_for(milliseconds(2000));

         std::lock_guard<std::mutex> guard(mmutex);

         flag = true;

         std::cout<<"Data is ready"<<std::endl;

         cvar.notify_one();

       }

       void task(){

       std::unique_lock<std::mutex> lock(mmutex);

       cvar.wait(lock, [&, this]() mutable throw() -> bool{ return this->isReady(); });

       mdata+=1;

       }

   protected:

    std::condition_variable cvar;
    std::mutex mmutex;
    int mdata;
    bool flag = false;

};

int main(){

     int a = 0;
     Product product(a);

     std::thread reading(product.read, &product);
     std::thread setting(product.task, &product);

     reading.join();
     setting.join();


     product.showData();
    return 0;
}

이러한 예에서, I는를 사용 unique_lock<muType>하여condition variable


답변

다른 사람들이 언급했듯이 std :: unique_lock은 뮤텍스의 잠금 상태를 추적하므로 잠금 생성 후까지 잠금을 연기하고 잠금이 파괴되기 전에 잠금을 해제 할 수 있습니다. std :: lock_guard는 이것을 허용하지 않습니다.

std :: condition_variable 대기 함수가 고유 한 잠금뿐만 아니라 lock_guard를 가져 가지 않아야 할 이유가 없습니다. 대기가 종료 될 때마다 (어떤 이유로 든) 뮤텍스가 자동으로 다시 획득되어 의미 위반이 발생하지 않기 때문입니다. 그러나 표준에 따르면 조건 변수와 함께 std :: lock_guard를 사용하려면 std :: condition_variable 대신 std :: condition_variable_any를 사용해야합니다.

편집 : 삭제 “pthreads 인터페이스 std :: condition_variable과 std :: condition_variable_any는 동일해야합니다.” gcc의 구현을 살펴보면 다음과 같습니다.

  • std :: condition_variable :: wait (std :: unique_lock &)은 unique_lock이 보유한 뮤텍스와 관련하여 기본 pthread 조건 변수에서 pthread_cond_wait ()를 호출합니다 (따라서 lock_guard에 대해 동일하게 수행 할 수는 있지만 표준이 아니기 때문에) 그것을 제공하지 않습니다)
  • std :: condition_variable_any는 뮤텍스 잠금이 아닌 객체를 포함하여 모든 잠금 가능 객체에서 작동 할 수 있습니다 (따라서 프로세스 간 세마포어로도 작동 할 수 있음)