ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • condition_variable::wait
    개발/C·C++ 2021. 7. 26. 01:19

    condition_variable는 생산자-소비자 모델에 쓰이는 클래스입니다. 멤버 함수인 wait 함수는 첫 번째 인자로 unique_lock을 받습니다. condition_variable 클래스는 오직 std::unique_lock<std::mutex>을 통해서만 작동합니다. 이러한 제한은 일부 플랫폼에서 최대 효율을 만들 수 있습니다. 두 번째 인자는 predicate을 넣어주는데, 특정 조건을 만족하기 전까지 해당 스레드는 블록되며 원자적으로 언락됩니다. 블록된 스레드는 notifiy_all()이나 notify_one()이 실행될 때 블록이 풀리는데, 때로는 그냥 풀릴 수도 있습니다(spuriously). 블록이 풀리면, 락이 다시 획득되고 대기가 끝납니다.

     

    예제 코드

    #include <iostream>
    #include <condition_variable>
    #include <thread>
    #include <chrono>
     
    std::condition_variable cv;
    std::mutex cv_m; // This mutex is used for three purposes:
                     // 1) to synchronize accesses to i
                     // 2) to synchronize accesses to std::cerr
                     // 3) for the condition variable cv
    int i = 0;
     
    void waits()
    {
        std::unique_lock<std::mutex> lk(cv_m);
        std::cerr << "Waiting... \n";
        cv.wait(lk, []{return i == 1;});
        std::cerr << "...finished waiting. i == 1\n";
    }
     
    void signals()
    {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        {
            std::lock_guard<std::mutex> lk(cv_m);
            std::cerr << "Notifying...\n";
        }
        cv.notify_all();
     
        std::this_thread::sleep_for(std::chrono::seconds(1));
     
        {
            std::lock_guard<std::mutex> lk(cv_m);
            i = 1;
            std::cerr << "Notifying again...\n";
        }
        cv.notify_all();
    }
     
    int main()
    {
        std::thread t1(waits), t2(waits), t3(waits), t4(signals);
        t1.join(); 
        t2.join(); 
        t3.join();
        t4.join();
    }
    Waiting...
    Waiting...
    Waiting...
    Notifying...
    Notifying again...
    ...finished waiting. i == 1
    ...finished waiting. i == 1
    ...finished waiting. i == 1

    wait 함수를 호출할 때 첫 번째 인자에 std::unique_lock<std::mutex>를 넣습니다. 두 번째 인자가 false를 반환할 경우 해당 스레드는 블록되고 락은 풀립니다. 때문에 t1, t2, t3 스레드는 wait 함수를 만나기 전까지 실행되고 블록됩니다(소비자). 생산자 쪽에서 i의 값을 1로 변경하고 notify_all 함수를 호출하면 모든 스레드의 wait 함수는 predicate을 검사합니다. 상태가 참이면 블록이 풀리면서 락을 얻고 실행 제어를 이어갑니다.

     

    signals 함수의 임계 영역 부분에 std::lock_guard가 사용됐습니다. 일반적으로 lock_guard를 사용하면 됩니다. 중요한 건 wait 함수에 넣는 락과 임계 영역에 사용되는 락의 뮤텍스 객체가 동일해야 한다는 점입니다. 같지 않으면 미정의 동작입니다. wait 함수를 호출할 때 락을 얻지 않는 것 또한 미정의 동작입니다. 

     

    출처

    https://en.cppreference.com/w/cpp/thread/condition_variable/wait

    '개발 > C·C++' 카테고리의 다른 글

    [자료구조] doubly linked list  (0) 2021.08.02
    [overloading] operator <<  (0) 2021.07.28
    Default arguments  (0) 2021.07.05
    [Template] 템플릿 구체화  (0) 2021.07.05
    [Priority queue] 간단한 참고  (0) 2021.07.03

    댓글

Designed by Tistory.