同步控制:condition_variable

条件变量

条件变量(condition_variable)用来实现多线程间的同步操作,控制多个线程的执行顺序。

操作作用
conditon_variable cv默认构造函数
~conditon_variable()析构函数
cv.notify_one()唤醒一个等待线程,若没有等待线程,通知则被丢弃。
cv.notify_all()唤醒所有等待线程
cv.wait(ul)使用unique_lock来等待通知
cv.wait(ul, pred)使用unique_lock来等待通知,直到唤醒时pred结果为true
cv.wait_for(ul, duration)在duration时间内使用unique_lock来等待通知
cv.wait_for(ul, duration, pred)在duration时间内使用unique_lock来等待通知,或直到唤醒时pred结果为true
cv.wait_until(ul, timepoint)在timepoint时间点前使用unique_lock来等待通知
cv.wait_until(ul, timepoint, pred)在timepoint时间点前使用unique_lock来等待通知,或直到唤醒时pred结果为true
例子
queue<int> queue;
mutex queMutex;
condition_variable queCV;

void provider(int val)
{
	for (int i = 0; i < 6; i ++)
	{
		{
			lock_guard<mutex> lg(queMutex);
			queue.push(val + 1);
		}
		queCV.notify_one();
		this_thread.sleep_for(chrono::milliseconds(val));
	}
}

void consumer(int num)
{
	while (true)
	{
		int val;
		{
			unique_lock<mutex> ul(queMutex);
			queCV.wait(ul, []{ return !queue.empty(); });
			val = queue.front();
			queue.pop();
		}
	}
}

int main()
{
	auto p1 = async(launch::async, provider, 100);
	auto p2 = async(launch::async, provider, 300);
	auto p3 = async(launch::async, provider, 500);

	auto c1 = async(launch::async, consumer, 1);
	auto c2 = async(launch::async, consumer, 2);
}

条件变量只是负责多线程的同步控制,资源的竞争访问还需要互斥锁,条件变量内部实现也使用了unique_lock。所以条件变量总是和互斥锁一起使用。

需要注意的是,代码中通知函数notify前使用的是lock_guard,而等待函数wait前使用的是unique_lock。

{
	lock_guard<mutex> lg(queMutex);
	queue.push(val + 1);
}
queCV.notify_one();
unique_lock<mutex> ul(queMutex);
queCV.wait(ul, []{ return !queue.empty(); });

unique_lock相比lock_guard更加灵活。lock_guard只能在构造函数中加锁,在析构函数中解锁;而unique_lock还可以在需要时调用lock或unlock进行加锁、解锁操作。等待函数wait阻塞时,会调用unique_lock的unlock函数释放锁,以使其他线程有机会获取锁。

另一个需要注意的是条件变量的虚假唤醒。虚假唤醒是指,由于操作系统的原因,条件变量的wait操作可能在条件变量未被notify通知时返回。所以需要进行二次检查。

queCV.wait(ul, []{ return !queue.empty(); });

wait函数内部会在条件变量被唤醒时调用第二实参,当它返回true时才会返回,否则再次进行等待。相当于:

while (queue.empty())
{
	queCV.wait(ul);
}

另外,如果调用wait时第二实参的返回值是true,那么wait不会等待而是马上返回。下面代码不调用notify函数也能正常运行。

auto lmb = [] {
	std::unique_lock<std::mutex> ul(m);
	cv.wait(ul, [] { return true; });
	std::cout << "test condition variable wait" << std::endl;
};

std::future<void> f = std::async(std::launch::async, lmb);

f.get();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值