condition_variable.notify_one ()을 호출하기 전에 잠금을 획득해야합니까?


90

사용에 대해 약간 혼란 스럽습니다 std::condition_variable. 전화하기 전에 unique_lock에 를 만들어야한다는 것을 이해 합니다. 내가 찾을 수없는 것은 나는 또한 호출하기 전에 고유 잠금을 획득해야하는지 여부입니다 또는 .mutexcondition_variable.wait()notify_one()notify_all()

cppreference.com의 예 는 상충됩니다. 예를 들어, notify_one 페이지 는 다음 예를 제공합니다.

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

std::condition_variable cv;
std::mutex cv_m;
int i = 0;
bool done = false;

void waits()
{
    std::unique_lock<std::mutex> lk(cv_m);
    std::cout << "Waiting... \n";
    cv.wait(lk, []{return i == 1;});
    std::cout << "...finished waiting. i == 1\n";
    done = true;
}

void signals()
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Notifying...\n";
    cv.notify_one();

    std::unique_lock<std::mutex> lk(cv_m);
    i = 1;
    while (!done) {
        lk.unlock();
        std::this_thread::sleep_for(std::chrono::seconds(1));
        lk.lock();
        std::cerr << "Notifying again...\n";
        cv.notify_one();
    }
}

int main()
{
    std::thread t1(waits), t2(signals);
    t1.join(); t2.join();
}

여기서 잠금은 첫 번째에 대해 획득되지 않고 notify_one()두 번째에 대해 획득됩니다 notify_one(). 예제가있는 다른 페이지를 살펴보면 대부분 잠금을 획득하지 않고 다른 것을 볼 수 있습니다.

  • 을 호출하기 전에 뮤텍스를 잠그도록 선택할 수 notify_one()있으며 왜 잠그도록 선택해야합니까?
  • 주어진 예에서 왜 첫 번째에 대한 잠금이 없지만 notify_one()후속 호출에 대한 잠금이 있습니다 . 이 예가 잘못되었거나 근거가 있습니까?

답변:


77

를 호출 할 때 잠금을 유지할 필요는 없지만 condition_variable::notify_one()여전히 잘 정의 된 동작이고 오류가 아니라는 점에서 잘못된 것은 아닙니다.

그러나 대기중인 스레드가 실행 가능 해지면 (있는 경우) 알림 스레드가 보유하는 잠금을 즉시 획득하려고 시도하므로 "비관적"일 수 있습니다. notify_one()또는 을 호출하는 동안 조건 변수와 관련된 잠금을 유지하지 않는 것이 좋은 경험 규칙이라고 생각합니다 notify_all(). Pthread Mutex를 참조하십시오 : pthread_mutex_unlock ()은notify_one() 성능 향상에 해당하는 pthread를 호출하기 전에 잠금을 해제하는 예제에 대해 많은 시간소비 합니다.

루프 상태 확인 중에 잠금을 유지해야하므로 루프 의 lock()호출이 while어느 시점에서 필요하다는 점 을 명심 while (!done)하십시오. 그러나에 대한 호출을 위해 보류 할 필요는 없습니다 notify_one().


2016-02-27 : 경쟁 조건이 있는지 여부에 대한 의견의 일부 질문을 해결하기위한 대규모 업데이트는 잠금이 notify_one()호출에 도움이되지 않습니다 . 거의 2 년 전에 질문을 받았기 때문에이 업데이트가 늦었다는 것을 알고 있지만 생산자 ( signals()이 예에서)가 notify_one()소비자 ( waits()이 예에서)가 전화 를하기 직전에 호출 하는 경우 가능한 경쟁 조건에 대한 @Cookie의 질문을 해결하고 싶습니다. 전화 할 수 wait()있습니다.

핵심은 무슨 일이 일어나는지입니다. 그것은 i소비자가 할 일이 있는지 여부를 실제로 나타내는 객체입니다. 는 condition_variable소비자가 효율적으로의 변경을 기다릴 수 있도록 단지 메커니즘입니다 i.

생산자는 업데이트 할 때 잠금을 유지 i해야하며 소비자는 확인 i하고 호출 하는 동안 잠금을 유지해야합니다 condition_variable::wait()(아주 기다려야하는 경우). 이 경우 핵심은 소비자가이 확인 및 대기를 수행 할 때 잠금을 유지하는 동일한 인스턴스 (종종 중요 섹션이라고 함) 여야 한다는 입니다. 중요 섹션은 생산자가 업데이트 i할 때와 소비자가를 확인하고 대기 할 때 유지되므로 소비자가를 확인하는 시점과 호출하는 시점 사이에 변경할 i기회가 없습니다 . 이것이 조건 변수의 적절한 사용을위한 핵심입니다.iicondition_variable::wait()

C ++ 표준에 따르면 condition_variable :: wait ()는 조건 자와 함께 호출 될 때 다음과 같이 작동합니다 (이 경우).

while (!pred())
    wait(lock);

소비자가 확인할 때 발생할 수있는 두 가지 상황이 있습니다 i.

  • 경우 i다음 소비자 호출 0 cv.wait(), 다음, i여전히 0이 될 것이다 wait(lock)구현의 일부를 호출 - 그 잠금 보장하지만의 적절한 사용. 이 경우 생산자는 소비자가 호출 할 때까지 루프 condition_variable::notify_one()에서 를 호출 할 기회가 없습니다 ( 호출이 알림을 제대로 '잡기'위해 수행해야하는 모든 작업을 수행했습니다.이를 완료 할 때까지 잠금을 해제하지 않습니다.) ). 따라서이 경우 소비자는 알림을 놓칠 수 없습니다.whilecv.wait(lk, []{return i == 1;})wait()wait()

  • 경우는 i소비자의 호출이 때 이미 1 cv.wait()wait(lock)때문에 구현의 일부가 호출되지 않습니다 while (!pred())테스트는 내부 루프가 종료하게됩니다. 이 상황에서는 notify_one () 호출이 언제 발생하는지는 중요하지 않습니다. 소비자는 차단하지 않습니다.

여기에있는 예제 done는 소비자가 그것을 인식했음을 생산자 스레드에 다시 알리기 위해 변수를 사용하는 추가적인 복잡성이 i == 1있지만, done(읽기 및 수정을 위해) 모든 액세스 권한이 있기 때문에 이것이 분석을 전혀 변경하지 않는다고 생각 합니다. ) icondition_variable.

당신이 지적 @ eh9하는 질문을 보면, 동기화 표준 : 원자 및 표준 : : condition_variable 사용 신뢰할 수없는 , 당신은 것입니다 경쟁 조건을 참조하십시오. 그러나이 질문에 게시 된 코드는 조건 변수를 사용하는 기본 규칙 중 하나를 위반합니다. 확인 및 대기를 수행 할 때 하나의 중요 섹션을 보유하지 않습니다.

이 예에서 코드는 다음과 같습니다.

if (--f->counter == 0)      // (1)
    // we have zeroed this fence's counter, wake up everyone that waits
    f->resume.notify_all(); // (2)
else
{
    unique_lock<mutex> lock(f->resume_mutex);
    f->resume.wait(lock);   // (3)
}

wait()을 누른 상태에서 at # 3이 수행되는 것을 알 수 f->resume_mutex있습니다. 그러나 wait()1 단계에서 필요한지 여부에 대한 확인은 해당 잠금을 전혀 유지하는 동안 수행 되지 않습니다 (확인 및 대기의 경우 훨씬 덜 연속적 임). 이는 조건 변수의 적절한 사용을위한 요구 사항입니다. 나는 그 코드 스 니펫에 문제가있는 사람이 그 이후 f->counterstd::atomic이것이 요구 사항을 충족시킬 것이라고 생각했다고 믿습니다 . 그러나에서 제공하는 원자 성은 std::atomic후속 호출로 확장되지 않습니다 f->resume.wait(lock). 이 예 f->counter에서는가 체크 된 시점 (1 단계)과 wait()호출 된 시점 (3 단계 ) 사이에 경쟁이 있습니다.

이 질문의 예에는 그 인종이 존재하지 않습니다.


2
더 깊은 의미가 있습니다 : domaigne.com/blog/computing/… 특히 언급 한 pthread 문제는 최신 버전이나 올바른 플래그로 빌드 된 버전으로 해결되어야합니다. ( wait morphing최적화 를 활성화하려면 )이 링크에 설명 된 경험 법칙 :보다 예측 가능한 결과를 위해 스레드가 2 개 이상인 상황에서는 WITH 잠금을 알리는 것이 좋습니다.
v.oddou 2014 년

6
@Michael : 내 이해를 위해 소비자는 결국 the_condition_variable.wait(lock);. 생산자와 소비자를 동기화하는 데 잠금이 필요하지 않은 경우 (예 : 기본이 잠금없는 spsc 대기열 인 경우) 생산자가 잠금을 설정하지 않으면 해당 잠금은 아무 소용이 없습니다. 괜찮아요. 하지만 희귀 한 종족에 대한 위험이 있지 않습니까? 생산자가 잠금을 유지하지 않으면 소비자가 대기 직전에있을 때 notify_one을 호출 할 수 없습니까? 그런 다음 소비자는 기다림에
Cookie

1
예를 들어 위의 코드에서 std::cout << "Waiting... \n";생산자가하는 동안 소비자가 있다고 말하면 cv.notify_one();깨우기 호출이 누락됩니다 ... 아니면 여기에 뭔가 누락되어 있습니까?
Cookie

1
@쿠키. 예, 거기에 경쟁 조건이 있습니다. stackoverflow.com/questions/20982270/…
eh9

1
@ eh9 : 젠장, 귀하의 의견 덕분에 때때로 내 코드를 동결시키는 버그의 원인을 찾았습니다. 이것은 경쟁 조건의 정확한 경우 때문이었습니다. 알림 후 뮤텍스를 잠금 해제하면 문제가 완전히 해결되었습니다 ... 감사합니다!
galinette 2016

10

상태

vc10 및 Boost 1.56을 사용하여이 블로그 게시물에서 제안하는 것과 거의 유사한 동시 대기열을 구현했습니다 . 작성자는 경합을 최소화하기 위해 뮤텍스를 잠금 해제합니다. 즉, notify_one()뮤텍스가 잠금 해제 된 상태로 호출됩니다.

void push(const T& item)
{
  std::unique_lock<std::mutex> mlock(mutex_);
  queue_.push(item);
  mlock.unlock();     // unlock before notificiation to minimize mutex contention
  cond_.notify_one(); // notify one waiting thread
}

뮤텍스 잠금 해제는 Boost 문서 의 예를 통해 뒷받침됩니다 .

void prepare_data_for_processing()
{
    retrieve_data();
    prepare_data();
    {
        boost::lock_guard<boost::mutex> lock(mut);
        data_ready=true;
    }
    cond.notify_one();
}

문제

여전히 이로 인해 다음과 같은 비정상적인 동작이 발생했습니다.

  • 반면이 notify_one()있다 없다 라고되어 아직 cond_.wait()여전히 통해 중단 될 수 있습니다boost::thread::interrupt()
  • 한 번 notify_one()처음으로 cond_.wait()교착 상태가 발생했습니다. boost::thread::interrupt()또는 boost::condition_variable::notify_*()더 이상 기다릴 수 없습니다 .

해결책

줄을 제거하면 mlock.unlock()코드가 예상대로 작동합니다 (알림 및 인터럽트로 인해 대기가 종료 됨). 참고 notify_one()범위를 떠날 때 여전히 잠겨 뮤텍스로 호출, 그것은 바로 이후에 잠금 해제 :

void push(const T& item)
{
  std::lock_guard<std::mutex> mlock(mutex_);
  queue_.push(item);
  cond_.notify_one(); // notify one waiting thread
}

즉, 적어도 내 특정 스레드 구현에서는 뮤텍스를 호출하기 전에 잠금을 해제해서는 안됩니다 boost::condition_variable::notify_one().


이 문제를 Boost.Thread에보고 했습니까? 비슷한 작업을 찾을 수 없습니다. svn.boost.org/trac/boost/…
magras

@magras 슬프게도 나는 이것을 고려하지 않은 이유를 모릅니다. 그리고 불행히도 언급 된 대기열을 사용하여이 오류를 재현하는 데 성공하지 못했습니다.
Matthäus Brandl

나는 일찍 일어나서 교착 상태를 일으킬 수 있는지 잘 모르겠습니다. 특히 push ()가 큐 뮤텍스를 해제 한 후 notify_one ()이 호출되기 전에 pop ()의 cond_.wait ()에서 나온 경우-Pop ()은 큐가 비어 있지 않은 것을보고 새 항목을 소비해야합니다. 기다리는. push ()가 큐를 업데이트하는 동안 cond_.wait ()에서 나오면 push ()에 의해 잠금이 유지되어야하므로 pop ()은 잠금이 해제 될 때까지 대기해야합니다. 다른 초기 웨이크 업은 pop ()이 다음 wait ()를 호출하기 전에 push ()가 큐를 수정하지 못하도록 잠금을 유지합니다. 내가 놓친 게 무엇입니까?
Kevin

4

다른 사람들이 지적했듯이 notify_one()경쟁 조건 및 스레딩 관련 문제와 관련하여을 호출 할 때 잠금을 유지할 필요가 없습니다 . 그러나 어떤 경우 condition_variable에는를 notify_one()호출 하기 전에 파괴 되는 것을 방지하기 위해 잠금을 유지해야 할 수 있습니다 . 다음 예를 고려하십시오.

thread t;

void foo() {
    std::mutex m;
    std::condition_variable cv;
    bool done = false;

    t = std::thread([&]() {
        {
            std::lock_guard<std::mutex> l(m);  // (1)
            done = true;  // (2)
        }  // (3)
        cv.notify_one();  // (4)
    });  // (5)

    std::unique_lock<std::mutex> lock(m);  // (6)
    cv.wait(lock, [&done]() { return done; });  // (7)
}

void main() {
    foo();  // (8)
    t.join();  // (9)
}

새로 생성 된 쓰레드 t를 생성 한 후 조건 변수를 기다리기 전에 ((5)와 (6) 사이에) 컨텍스트 전환이 있다고 가정합니다 . 스레드 t는 잠금 (1)을 획득하고 조건 자 변수 (2)를 설정 한 다음 잠금을 해제합니다 (3). notify_one()(4)가 실행 되기 전에이 시점에서 다른 컨텍스트 전환이 있다고 가정합니다 . 주 스레드는 잠금 (6)을 획득하고 줄 (7)을 실행합니다.이 지점에서 술어가 리턴 true되고 기다릴 이유가 없으므로 잠금을 해제하고 계속합니다. foo(8)을 반환하고 해당 범위의 변수 (포함 cv)가 삭제됩니다. 쓰레드 t가 메인 쓰레드 (9)에 합류 하기 전에 실행을 완료해야하므로 실행을 중단 한 지점부터 계속됩니다.cv.notify_one()(4), 어느 시점 cv에서 이미 파괴되었습니다!

이 경우 가능한 해결 방법은 호출 할 때 잠금을 유지하는 것입니다 notify_one(예 : 줄 (3)로 끝나는 범위 제거). 그렇게함으로써, 검사  를 수행하기 위해 현재 보유하고 있는 잠금을 획득해야하기 때문에 이전 스레드 t호출 이 새로 설정된 술어 변수를 확인하고 계속할 수 있는지 확인합니다 . 따라서 반환 후 스레드에 의해 액세스되지 않도록 합니다.notify_onecv.waittcvtfoo

요약하면이 특정 경우의 문제는 실제로 스레딩에 관한 것이 아니라 참조로 캡처 된 변수의 수명에 관한 것입니다. cv스레드를 통해 참조로 캡처 t되므로 cv스레드 실행 기간 동안 활성 상태를 유지 해야 합니다. 여기에 제시된 다른 예제는이 문제가 발생하지 않습니다. 왜냐하면 condition_variablemutex객체는 전역 범위에서 정의 되기 때문입니다 . 따라서 프로그램이 종료 될 때까지 활성 상태로 유지됩니다.


1

@Michael Burr가 맞습니다. condition_variable::notify_one변수에 대한 잠금이 필요하지 않습니다. 예제에서 보여 주듯이 그 상황에서 잠금을 사용하는 것을 방해하는 것은 없습니다.

주어진 예에서 잠금은 변수의 동시 사용에 의해 동기가 부여됩니다 i. signals스레드 가 변수를 수정 하기 때문에 해당 시간 동안 다른 스레드가 변수에 액세스하지 못하도록해야합니다.

잠금은 동기화가 필요한 모든 상황에 사용됩니다 . 좀 더 일반적인 방식으로 설명 할 수는 없다고 생각합니다.


물론 전체 패턴이 실제로 작동하도록 조건 변수와의 결합에서 사용해야합니다. 특히 조건 변수 wait함수는 호출 내에서 잠금을 해제하고 잠금을 다시 획득 한 후에 만 ​​반환합니다. 그 후에는 "읽기 권한"을 획득했기 때문에 귀하의 상태를 안전하게 확인할 수 있습니다. 여전히 기다리고있는 것이 아니라면로 돌아갑니다 wait. 이것이 패턴입니다. btw,이 예는 그것을 존중하지 않습니다.
v.oddou 2014 년

1

어떤 경우에는 cv가 다른 스레드에 의해 점유 (잠김) 될 수 있습니다. notify _ * () 전에 잠금을 설정하고 해제해야합니다.
그렇지 않은 경우 notify _ * ()는 전혀 실행되지 않을 수 있습니다.


1

받아 들인 답변이 오해의 소지가 있다고 생각하기 때문에이 답변을 추가하십시오. 실제로 notify _ * ()를 호출하기 전에 다시 잠금을 해제 할 수 있지만, 모든 경우에 스레드로부터 안전한 코드를 위해 notify_one ()을 어딘가 에서 호출하기 전에 뮤텍스를 잠 가야 합니다.

명확히하기 위해 wait ()가 lk를 잠금 해제하고 잠금이 잠기지 않은 경우 정의되지 않은 동작이되기 때문에 wait (lk)에 들어가기 전에 잠금을 가져와야합니다. 이는 notify_one ()의 경우가 아니지만 wait ()를 입력 하고 해당 호출이 뮤텍스를 잠금 해제 하기 전에 notify _ * ()를 호출하지 않도록해야합니다 . 이는 notify _ * ()를 호출하기 전에 동일한 뮤텍스를 잠 가야만 수행 할 수 있습니다.

예를 들어 다음과 같은 경우를 고려하십시오.

std::atomic_int count;
std::mutex cancel_mutex;
std::condition_variable cancel_cv;

void stop()
{
  if (count.fetch_sub(1) == -999) // Reached -1000 ?
    cv.notify_one();
}

bool start()
{
  if (count.fetch_add(1) >= 0)
    return true;
  // Failure.
  stop();
  return false;
}

void cancel()
{
  if (count.fetch_sub(1000) == 0)  // Reached -1000?
    return;
  // Wait till count reached -1000.
  std::unique_lock<std::mutex> lk(cancel_mutex);
  cancel_cv.wait(lk);
}

경고 :이 코드에는 버그가 있습니다.

아이디어는 다음과 같습니다. 스레드는 start ()와 stop ()을 쌍으로 호출하지만 start ()가 true를 반환하는 동안에 만 호출됩니다. 예를 들면 :

if (start())
{
  // Do stuff
  stop();
}

어느 시점에서 하나의 (다른) 스레드는 cancel ()을 호출하고 cancel ()에서 반환 된 후 'Do stuff'에 필요한 객체를 파괴합니다. 그러나 cancel ()은 start ()와 stop () 사이에 스레드가있는 동안에는 반환되지 않아야하며 cancel ()이 첫 번째 줄을 실행하면 start ()는 항상 false를 반환하므로 새 스레드가 'Do 물건 '영역.

제대로 작동합니까?

그 이유는 다음과 같습니다.

1) 어떤 스레드가 start ()의 첫 번째 줄을 성공적으로 실행하면 (따라서 true를 반환) 아직 cancel ()의 첫 번째 줄을 실행 한 스레드가없는 것입니다 (총 스레드 수가 1000보다 훨씬 작다고 가정합니다. 방법).

2) 또한 스레드가 start ()의 첫 번째 줄을 성공적으로 실행했지만 stop ()의 첫 번째 줄은 아직 실행하지 않은 경우 모든 스레드가 cancel ()의 첫 번째 줄을 성공적으로 실행하는 것은 불가능합니다 (단 하나의 스레드 만 cancel ()) 호출 : fetch_sub (1000)에서 반환 된 값은 0보다 큽니다.

3) 스레드가 cancel ()의 첫 번째 줄을 실행하면 start ()의 첫 번째 줄은 항상 false를 반환하고 start ()를 호출하는 스레드는 더 이상 'Do stuff'영역에 들어 가지 않습니다.

4) start () 및 stop ()에 대한 호출 수는 항상 균형을 이루므로 cancel ()의 첫 번째 줄이 성공적으로 실행되지 않은 후 stop ()에 대한 (마지막) 호출이 카운트를 일으키는 순간이 항상 있습니다. -1000에 도달하면 notify_one ()이 호출됩니다. 취소의 첫 번째 줄이 해당 스레드를 통과 한 경우에만 발생할 수 있습니다.

너무 많은 스레드가 start () / stop ()을 호출하여 카운트가 -1000에 도달하지 않고 cancel ()이 반환되지 않는 기아 문제를 제외하고는 "가능성이 낮고 오래 지속되지 않음"으로 받아 들일 수 있습니다. 또 다른 버그가 있습니다.

'Do stuff'영역 안에 하나의 스레드가있을 수 있습니다. stop (); 그 순간 스레드는 fetch_sub (1000)로 값 1을 읽고 통과하는 cancel ()의 첫 번째 줄을 실행합니다. 그러나 뮤텍스를 취하거나 wait (lk)를 호출하기 전에 첫 번째 스레드는 stop ()의 첫 번째 줄을 실행하고 -999를 읽고 cv.notify_one ()을 호출합니다!

그런 다음 notify_one ()에 대한이 호출은 조건 변수에서 wait ()-ing하기 전에 수행됩니다! 그리고 프로그램은 무기한 교착 상태가됩니다.

이런 이유로 wait ()를 호출 할 때까지 notify_one ()을 호출 할 수 없어야합니다 . 조건 변수의 힘은 뮤텍스를 원자 적으로 잠금 해제하고 notify_one () 호출이 발생했는지 확인하고 절전 모드로 전환 할 수 있다는 점에 있습니다. 당신은 그것을 속일 수 있지만, 당신은 어떻게 당신이 false에서 true로 조건을 변경하고 있습니다 변수를 변경 할 때마다 뮤텍스가 잠겨 유지하는 필요성을 유지 여기에 설명 된 것처럼 때문에 경쟁 조건의 notify_one ()를 호출하는 동안 잠겨 있습니다.

그러나이 예에서는 조건이 없습니다. 왜 'count == -1000'조건으로 사용하지 않았습니까? 여기서는 전혀 흥미롭지 않기 때문입니다. -1000에 도달하자마자 새 스레드가 'Do stuff'영역에 들어 가지 않을 것입니다. 게다가 스레드는 여전히 start ()를 호출 할 수 있고 카운트를 증가시킬 것입니다 (-999 및 -998 등).하지만 우리는 그것에 대해 신경 쓰지 않습니다. 중요한 것은 -1000에 도달했기 때문에 'Do stuff'영역에 더 이상 스레드가 없음을 확실히 알 수 있다는 것입니다. 우리는 notify_one ()이 호출되는 경우라고 확신하지만 cancel ()이 뮤텍스를 잠그기 전에 notify_one ()을 호출하지 않는지 확인하는 방법은 무엇입니까? 물론 notify_one () 직전에 cancel_mutex를 잠그는 것은 도움이되지 않습니다.

문제는 우리가 조건을 기다리지 않고 있다는 것을에도 불구하고, 여전히,이다 조건, 우리는 뮤텍스를 잠글 필요

1) 해당 조건에 도달하기 전 2) notify_one을 호출하기 전.

따라서 올바른 코드는 다음과 같습니다.

void stop()
{
  if (count.fetch_sub(1) == -999) // Reached -1000 ?
  {
    cancel_mutex.lock();
    cancel_mutex.unlock();
    cv.notify_one();
  }
}

[... 동일한 start () ...]

void cancel()
{
  std::unique_lock<std::mutex> lk(cancel_mutex);
  if (count.fetch_sub(1000) == 0)
    return;
  cancel_cv.wait(lk);
}

물론 이것은 하나의 예일 뿐이지 만 다른 경우는 매우 유사합니다. 당신은 당신이하는 조건 변수를 사용하는 거의 모든 경우에 필요한 그 뮤텍스를 가지고)를 notify_one을 (호출하기 전에 (곧) 잠금, 그렇지 않으면 당신이 대기를 호출하기 전에 ()를 호출하는 것이 가능하다.

이 경우에는 notify_one ()을 호출하기 전에 뮤텍스를 잠금 해제했습니다. 블록, 뮤텍스를 다시 해제하기 전에. 필요한 것보다 약간 느립니다.

이 예제는 조건을 변경하는 라인이 wait ()를 호출하는 동일한 스레드에 의해 실행된다는 점에서 좀 특별했습니다.

보다 일반적인 경우는 한 스레드가 단순히 조건이 참이 될 때까지 기다리고 다른 스레드가 해당 조건과 관련된 변수를 변경하기 전에 잠금을 취하는 경우입니다 (이로 인해 참이 될 수 있음). 이 경우 뮤텍스 조건이 참이되기 직전과 직후 잠 깁니다 . 따라서이 경우에는 notify _ * ()를 호출하기 전에 뮤텍스를 잠금 해제해도됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.