lock
을 얻은 뒤 해당 쓰레드를 계속 실행시키고 아닐경우 다시 wait()
을 발생시켜 대기하는 일을 할 때 주로 쓰인다.조건 변수를 대기하는 코드에서는 mutex를 사용해야 합니다. 조건 변수를 대기하는 함수를 호출하기 전에 호출 스레드에서 mutex를 잠가야 합니다. 호출된 함수가 반환될 때 mutex가 잠깁니다. 스레드가 조건이 true가 될 때까지 대기하는 동안에는 mutex가 잠기지 않습니다. 예기치 않은 결과가 없도록 조건 변수를 대기하는 각 스레드는 동일한 mutex 개체를 사용해야 합니다.
condition_variable_any 형식의 개체는 모든 종류의 뮤텍스와 함께 사용할 수 있습니다. 사용되는 뮤텍스의 형식에서 try_lock 메서드를 제공할 필요가 없습니다. condition_variable 형식의 개체만 unique_lock 형식의 뮤텍스와 함께 사용할 수 있습니다. 이 형식의 개체는 condition_variable_any<unique_lock> 형식의 개체보다 빠를 수 있습니다.
이벤트를 대기하려면 먼저 뮤텍스를 잠근 후 조건 변수에 대한 wait 메서드 중 하나를 호출합니다. 다른 스레드가 조건 변수를 알릴 때까지 wait에서 블록을 호출합니다.
조건 변수를 대기 중인 스레드가 적절한 알림 없이 차단 해제될 때 의사 대기 모드 해제가 발생합니다. 이러한 의사 대기 모드 해제를 인식하기 위해 대기 함수에서 코드가 반환될 때 조건이 true가 될 때까지 대기하는 코드에서 해당 조건을 명시적으로 확인해야 합니다. 이는 보통 루프를 사용하여 수행됩니다. wait(unique_lock& lock, Predicate pred)를 사용하여 이 루프를 자동으로 수행할 수 있습니다.https://docs.microsoft.com/ko-kr/cpp/standard-library/condition-variable?view=msvc-170
#include <iostream>
#include <thread>
#include <mutex>
#include <Windows.h>
mutex m;
queue<int32> q;
//커널 오브젝트: 커널에서 관리하는 객체 -> 같은 프로세스가 아닌 다른프로세스랑 동기화할때 유용하게 쓰인다.
// spinlock같은 기법은 유저레벨에서 동기화가 일어나는것이지만
// 이벤트를 이용해서 커널오브젝트까지 이용해서 하는것은 너무 빈번하게 일어나는경우 비용(리소스 사용량)이 너무 높아진다.
//따라서 condition_variable을 써보자
//유저레벨 오브젝트다! not kernel object!
condition_variable cv;
void Push() {
while (true)
{
//1) lock을 잡고
//2) 공유 변수 값을 수정
// 3) 락을 풀고
//4) 조건변수 통해 다른 쓰레드에게 통지
{//lock 범위용 블록 처리
unique_lock<mutex> lock(m);
q.push(100);
}
//::SetEvent(handle);
cv.notify_one();
//this_thread::sleep_for(10000ms);
}
}
void Pop() {
while (true)
{
//::WaitForSingleObject(handle, INFINITE);//signal이 올때까지 대기, 수면(InNFINITE-> 무한정대기)
//스케쥴의 대상이 되지않는다!!. 따라서 CPU점유률이 거의 0까지 떨어진다.
// Non-signal event의 manualReset옵션을 false로 해두었으니 자동으로 signal->non-signal로 바뀜
// 만약 매뉴얼의 세팅값이 TRUE이면 ::ResetEvent(handle)을 호출해서 강제로 리셋해야된다.
unique_lock<mutex> lock(m);//유니크 락만 cv.wait을 가능케한다. 왜냐면 락을 중간에 풀고 다시 잡고해야되는데 유닠락만 가등한 기능이기때문
cv.wait(lock, []() {return q.empty() == false; });
//1) lock을 잡고
//2) 조건확인
// - 만족O => 빠져나와서 이어서 코드를 진행
// - 만족X => 락을 풀어주고 대기 상태
//if (q.empty() == false)
{
int32 data = q.front();
q.pop();
cout << q.size() << endl;
}
}
}
int main()
{
thread t1(Push);
thread t2(Pop);
t1.join();
t2.join();
}