条件变量用于等待特定条件下的线程唤醒,通常和互斥锁搭配使用。mutex 一般以抢占方式保护资源,但如果希望让某个线程先执行,再让另一个线程执行,就可以借助条件变量来协调。

在使用条件变量时,等待一方仍然必须持有 mutex。调用等待函数之前,线程要先锁定 mutex,再调用条件变量的等待方法;当等待函数返回时,mutex 会处于被阻塞的状态。当线程等待条件变为 true 的过程中,mutex 并没有被持续锁定。为了避免不可预知的结果,所有等待同一个条件变量的线程都必须使用同一个 mutex 对象。

condition_variable 与 condition_variable_any 的区别

类型 condition_variable_any 的对象可以搭配任意类型的 mutex 使用,对应的 mutex 类型也不要求必须提供 try_lock 方法。相比之下,类型 condition_variable 的对象只能与 unique_lock<mutex> 搭配使用;这一类型的对象通常比 condition_variable_any<unique_lock<mutex>> 的对象更快一些。

要等待某个事件,先锁定 mutex,再调用条件变量的 wait 方法。该调用会一直阻塞,直到另一个线程在同一个条件变量上触发通知为止。

虚假唤醒

当等待条件变量的线程在没有收到相应通知的情况下被取消时,就会出现所谓的"虚假"唤醒。为了识别这种情况,在等待函数返回之后,代码需要显式地再次检查条件是否真的为 true。通常的做法是把检查放在循环里;也可以使用 wait(unique_lock<mutex>& lock, Predicate pred) 这种带谓词的重载,由标准库自动帮你完成循环检查。

读线程等待写线程完成后被唤醒

.
//读线程等待写线程完毕后 唤醒

std::mutex _mutex;//全局互斥锁

std::condition_variable_any condition;//全局条件变量

int x = 1;//全局资源

void func_1()//write thread
{
	Sleep(100);

        {
	    lock_guard<std::mutex> lock(_mutex);
	    x += 1;
        }
	condition.notify_one(); //唤醒,等待写入而挂起的读线程

}

void func_2()//read thread
{
	unique_lock<std::mutex>lock(_mutex) ;

	condition.wait(_mutex);//挂起该线程,等待修改完数据的线程唤醒,
	cout << x << endl;

}


int main(int argc, char *argv[])
{

	auto t = std::thread(func_1);//写线程

	t.detach();

	auto t1 = std::thread(func_2);//读线程

	t1.detach();

	Sleep(300);

	cout << x << endl;
	cout << "main thread" << endl;



	system("pause");
	return 0;
}

condition_variable 只能和 std::mutex 搭配使用,而 condition_variable_any 的适用范围更广。

几种不同的等待方式


	std::thread t([&]
	{
		while (true)
		{
			while (1)
			{
				mm.lock();

				con.wait(mm, [&](){return !_queue.empty(); });//被通知后,第二个参数返回值是true的时候
                //  才会解除阻塞
				cout << "getMsg" << endl;
				mm.unlock();

			}



			while (_queue.empty())
			{
				mm.lock();
				con.wait_for(mm,std::chrono::milliseconds(100));//固定时间的等待

				cout << "getMsg" << endl;
				mm.unlock();

			}


	        while (_queue.empty())
			{
				mm.lock();
				con.wait_for(mm));//一直等待直到 被通知

				cout << "getMsg" << endl;
				mm.unlock();

			}
		}

	});

	t.detach();

MSDN 参考:https://msdn.microsoft.com/zh-cn/library/hh874761(v=vs.120).aspx