하아찡

[C++ 11] condition variable(조건 변수) 본문

C++/추가공부

[C++ 11] condition variable(조건 변수)

하아찡 2024. 12. 27. 18:50

안녕하세요.

이번에는 condition variable를 알아보겠습니다.

이전에 알아봤던 Event에서 CreateEvent를 사용해서 커널단에 이벤트를 등록하는 방식으로 처리를 해봤습니다.

해당방식은 다른 프로세스에게도 이벤트를 전달 할 수 있는데, 나는 내 프로그램 내부에서만 처리가능하면 될거같은데 너무 무겁게 작업하는거 아닌가? 라는 생각을 할 수 있습니다.

그래서 있는게 condition variable입니다.

condition variable는 유저 모드 이벤트를 생성 및 호출을 하게 가능하게 됩니다.

사실 유저모드에서 이벤트가 발생하고 처리가 되는건 아닙니다. 실질적으로 이벤트가 발생했을때는 커널모드의 개입이 필요한데 그 외의 작업들이 유저모드에서 처리가 되기때문에 CreateEvent를 사용해서 이벤트를 생성하는 방식보다 훨씬 더 가볍습니다.

 

일다 그러면 사용방법을 보시죠

condition variable 맴버함수에는

waitnotify_one가 있습니다. 물론 더있는데 두가지만 살펴보겠습니다.

notify_once는 기다리고있는 쓰레드 한개를 깨워서 진행하게 합니다.

wait는 condition variable를 통해서 통지를 받기전까지 대기를합니다.

통지를 받아도 추가적으로 조건이 맞아야 작동하게도 할 수 있습니다.

 

더욱 다양한 함수를 살펴보시고싶으면 밑에 블로그를 추천드리겠습니다.

https://jungwoong.tistory.com/92

 

[c++] condition variable(조건 변수)

이번 글에서는 std::condition_variable에 대해서 설명드립니다. 설명 및 기본 동작 std::condition_variable condition_variable 클래스는 다른 스레드가 공유 변수를 수정하고 condition_variable로 통지할 때까지 스레

jungwoong.tistory.com

 

void wait(unique_lock<mutex>& _Lck);

template <class _Predicate>
void wait(unique_lock<mutex>& _Lck, _Predicate _Pred);

wait를 잘 살펴보면 wait는 lock_gurad를 사용하지못합니다. 대신 다른 unique_lock을 사용하게 되는데,

그 이유는 unique_lock은 Lock을 잡는 시점을 설정을 할 수 있습니다. 해당 이유로 lock_gurad대신 unique_lock을 사용하셔서 전달시켜 줘야합니다.

 

 

#include "pch.h"
#include <thread>
#include <atomic>
#include <mutex>
#include <Windows.h>
#include <condition_variable>

condition_variable cv;
queue<int32> q;
mutex m;
void Producer() {
    while (true) {
        {
            unique_lock<mutex> guard(m);
            q.push(100);
        }

        cv.notify_one();
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
}

void Consumer(int32 index) {
    while (true) {
        unique_lock<mutex> guard(m);
        cv.wait(guard, []() {return q.empty() == false; }); //한번더 확인 틀리면 lock을 다시 해제하고 대기상태.
        if (q.empty() == false) {
            //값이 있으면 빼온다
            int32 data = q.front();
            q.pop();
            cout << data << endl;
        }
    }
}
int main()
{
    

    std::thread t1(Producer);
    std::thread t2(Consumer,1);
    std::thread t3(Consumer,2);
    std::thread t4(Consumer,3);
    std::thread t5(Consumer,4);


    
    if (t1.joinable()) {
        t1.join();
    }
    if (t2.joinable()) {
        t2.join();
    }
    if (t3.joinable()) {
        t3.join();
    }
    if (t4.joinable()) {
        t4.join();
    }
    if (t5.joinable()) {
        t5.join();
    }


}

 

저는 wait에 조건부를 사용한 방식을 보여드리겠습니다.

주석처리를 해두었지만 다시한번 살펴보면

cv.wait(guard, []() {return q.empty() == false; });

위코드를 보면 wait로 락을 잡았어도

q.empty() == false가 맞지 않으면 잡았던 락을 풀어버립니다.

반응형

'C++ > 추가공부' 카테고리의 다른 글

[C++] 메모리 모델  (0) 2024.12.27
[C++] Event  (0) 2024.12.27
[C++ 11] SleepLock  (1) 2024.12.27
[C++ 11]std::atomic, SpinLock  (1) 2024.12.27
Volatile 예약어  (0) 2024.10.30