C++ Condition variable

如果你的线程需要

  1. 改变某个变量,改动完成之后通知另一个线程
  2. 持续等待,直到收到某一个线程发来的通知

那么就可以放心食用std::condition_variable了。

下面用一个例子来介绍什么是condition variable以及怎么使用:

妈妈和儿子的故事:
儿子在外面玩,衣服脏了。
儿子说:“妈妈帮我洗衣服”。
妈妈说:“好的吧”。

那么总结起来,可以用两个functions来表示这个故事:

  • 妈妈洗衣服 = void clean_laundry()
  • 儿子在外面玩,让妈妈洗衣服 = void play_around()

首先我们定义好如下一些变量和辅助functions:

std::mutex mtx;
std::condition_variable CV;
enum laundry {clean, dirty};
laundry son_laundry = laundry::clean;

bool is_laundry_clean(){
	return son_laundry == laundry::clean;
}

bool is_laundry_dirty(){
	return son_laundry == laundry::dirty;
}

这个就是我们故事的第一个functions,它会检查儿子当前的衣服是不是脏的。
如果是脏的,就将其清洗。
如果不是脏的,就等待儿子将衣服弄脏了然后清洗。

void clean_laundry(){
	std::unique_lock<std::mutex> lock(mtx);
	// wait() function会检查传入的is_laundry_dirty是否为真
	// true: wait()返回,继续执行下一步
	// false: wait()会解锁,把当前的锁让给别的线程,自己进入等待状态
	CV.wait(lock, is_laundry_dirty);
	
	std::cout << "mom: okay, I will clean your laundry" << std::endl;
	son_laundry = laundry::clean;
	std::cout << "mom: the laundry is clean now" << std::endl;

	// 因为要通知其他线程来继续执行,而其他线程需要当前这个mutex的lock才可以执行,所以必须要先将当前mutex解锁
	lock.unlock();

	// notify_one()会唤醒调用wait(mutex, condition)之后陷入等待的线程。
	// 被唤醒的线程需要重新获取mutex lock,并且再次检查传入的条件是否为真
	// 如果为true,线程继续执行,如果为false,线程继续等待
	CV.notify_one();
}

故事的第二个functions,儿子在外面玩,如果将衣服弄脏了,就告诉妈妈让她清洗,在衣服洗好前,儿子都不能出去玩(因为没有衣服换了)。
直到妈妈通知他,衣服已经洗好了。

void play_around(){
	std::cout << "Son is playing around and has laundry dirty" << std::endl;
	{
		std::lock_guard<std::mutex> lock(mtx);
		son_laundry = laundry::dirty;
	}
	
	std::cout << "son: hey mom, can you please help me clean the laundry?" << std::endl;
	
	// son tells his mom that his laundry is dirty now
	CV.notify_one();

	{
		std::unique_lock<std::mutex> lock(mtx);
		// 如果is_laundry_clean是true: 那么儿子可以结束等待,出去玩
		// 如果is_laundry_clean是false;儿子必须一直等待
		CV.wait(lock, is_laundry_clean);
	}

	std::cout << "son: wow, I get a clean laundry, thank you mom!" << std::endl;
}

注意,condition variable只能和std::unique_lock一起使用。具体请参见C++ Locks

可以看到,线程clean_laundry()和play_around()这两个线程都需要:

  1. 改变某个变量,改动完成之后通知另一个线程
  2. 持续等待,直到收到某一个线程发来的通知

所以它们使用condition variable来相互通信:
clean_laundry在son_laundry = laundry::dirty的时候执行,在son_laundry = laundry::clean的时候等待。
play_around在son_laundry = laundry::clean的时候执行,在son_laundry = dirty的时候等待。

最后,我们可以试验一下上面的程序:

int main(){
	std::thread mother(clean_laundry);
	std::thread son(play_around);
	
	mother.join();
	son.join();

	return 0;
}

结果如下,一个完整的故事:

Son is playing around and has laundry dirty
son: hey mom, can you please help me clean the laundry?
mom: okay, I will clean your laundry
mom: the laundry is clean now
son: wow, I get a clean laundry, thank you mom!
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值