c++多线程(九) - condition_variable

    条件变量(condition_variable)是一个和条件相关的类,通常和互斥量配合使用。

    本文主要介绍条件变量的两个函数wait() 和notify_one()。

1.wait()和notify_one()

    wait() 阻塞程序,等待条件的达成。notify_one() 把被阻塞在wait()的线程唤醒。

    在库函数中,函数wait有两个重载。

void wait(unique_lock<mutex>& _Lck)
{	// wait for signal
    _Cnd_waitX(_Mycnd(), _Lck.mutex()->_Mymtx());
}

template<class _Predicate>
void wait(unique_lock<mutex>& _Lck, _Predicate _Pred)
{	// wait for signal and test predicate
    while (!_Pred())
        wait(_Lck);
}

    函数有两个参数,程序执行到wait()语句时:

    (1).对互斥量加锁。

    (2).执行第二个参数表示的函数 _Pred。

    (3).函数 _Pred 返回false时,对互斥量解锁,程序阻塞,等待其它线程调用nofify_one()将其唤醒后,回到步骤(1)。

    (4).函数 _Pred返回true时,程序继续执行。

    函数只有一个参数,程序执行到wait()语句时阻塞(相当于第二参数表示的函数始终返回false),等待其它线程调用nofify_one()将其唤醒后,再继续执行(相当于第二参数表示的函数始终返回true)。

2. 代码实例

#include<iostream>
#include<thread>
#include<mutex>
#include<list>
using namespace std;

class MsgManage
{
public:
	MsgManage() {}
	~MsgManage() {}
	void InMsg()
	{
		for (int i = 0; i < 10000; i++)
		{
			cout << "插入元素: " << i << endl;
			std::unique_lock<std::mutex> guard(myMutex);
			myList.push_back(i);
			//把被阻塞在wait()的线程唤醒
			condition.notify_one();
		}
	}
	
	void OutMsg()
	{
		int num;
		while (true)
		{
			std::unique_lock<std::mutex> guard(myMutex);
			//列表为空时,对互斥量解锁,程序阻塞,等待被唤醒。
			//列表不为空时,程序继续执行。
			condition.wait(guard, [this] {
				if (!myList.empty())
					return true;
				return false;
			});
			//程序执行到这里,列表不为空,且互斥量已被加锁
			num = myList.front();
			myList.pop_front();
			//解锁,避免互斥量被锁住太长时间
			guard.unlock(); 
			cout << "移除元素: " << num << endl;

			//程序继续执行其它耗时代码
		}		
	}
private:
	list<int> myList;
	mutex myMutex;
	condition_variable condition;  //条件变量对象和互斥量配合使用
};

int main()
{
	MsgManage manage;
	thread outMsg(&MsgManage::OutMsg, &manage);
	thread inMsg(&MsgManage::InMsg, &manage);
	inMsg.join();
	outMsg.join();
	return 0;
}

3. 存在问题

    上述代码很好的演示了程序的阻塞和唤醒,减少了很多无意义的条件判断。但是依然存在一些问题。

    (1)  执行notify_one() 时,如果没有线程阻塞在wati()时,此次唤醒就没有实际效果。

  (2)当函数InMsg()执行完10000次循环后,不再会执行notify_one(),此时很可能有线程阻塞在wait()上,永远不会被唤醒了。

    对于此问题,后续的文章中会做进一步改进。

猜你喜欢

转载自blog.csdn.net/liyazhen2011/article/details/88603161