SW/C++

C++ : condition_variable::wait() : 사용법, 주의사항, 예제, 활용 방법

얇은생각 2020. 3. 30. 07:30
반응형

C++

 

std::condition_variable::wait

현재 쓰레드 뮤텍스의 잠금을 풀고 notifu_one() 또는 notify_all()을 기다립니다.

깨어나면, 뮤텍스를 다시 잠급니다.

 

 

 

다시말해, notify_xxx가 wait()보다 먼저 호출되면, 해당 쓰레드는 풀리지 않고, 영원히 기다리게 됩니다.

#include <iostream>
#include <mutex>
#include <queue>

static std::mutex sQueueLock;
static std::condition_variable sEvent;
static std::queue<int> sQueue;

void Consume()
{
	while (true)
	{
		int val;
		{
			std::unique_lock<std::mutex> lock(sQueueLock);
			sEvent.wait(lock);

			val = sQueue.front();
			sQueue.pop();
		}

		std::cout << val << std::endl;
	}
}

void Produce()
{
	std::unique_lock<std::mutex> lock(sQueueLock);
	sQueue.push(1);

	sEvent.notify_one();
}


int main()
{
	std::thread producer(Produce);
	std::thread consumer(Consume);

	consumer.join();
	producer.join();

	return 0;
}

 

 

 

Predicate 변수를 활용해 잘못 깨어날 위험을 줄입니다. 잠긴 두 쓰레드 모두에서 접근할 수 있는 bool 변수의 역할을 합니다. 해당 문제를 해결한 예제는 아래와 같습니다.

#include <iostream>
#include <mutex>
#include <queue>

static std::mutex sQueueLock;
static std::condition_variable sEvent;
static std::queue<int> sQueue;

void Consume()
{
	while (true)
	{
		int val;
		{
			std::unique_lock<std::mutex> lock(sQueueLock);
			sEvent.wait(lock, [] {return !sQueue.empty(); });

			val = sQueue.front();
			sQueue.pop();
		}

		std::cout << val << std::endl;
	}
}

void Produce()
{
	std::unique_lock<std::mutex> lock(sQueueLock);
	sQueue.push(1);

	sEvent.notify_one();
}


int main()
{
	std::thread producer(Produce);
	std::thread consumer(Consume);

	consumer.join();
	producer.join();

	return 0;
}

 

 

lock만 쓰는 것은 충분하지 않는 경우가 많습니다. 조건 변수가 신호를 받기 전에 대기 상태에 들어가는 것을 보장할 수 없을 수 있습니다. 이 떄, 항상 bool 조건과 lcok을 같이 활용해야 합니다. 위의 방식을 참조하여 구현하도록 하겠습니다.

반응형