C++11并发与多线程笔记(8) condition_variable、wait、notify_one、notify_all
- 1、条件变量condition_variable、wait、notify_one、notify_all
- 1.1 std::condition_variable
- 1.2 wait()
- 1.3 notify_one()
- 1.4 notify_all()
- 2、深入思考
1、条件变量condition_variable、wait、notify_one、notify_all
1.1 std::condition_variable
实际上是一个类,是一个和条件相关的类,说白了就是等待一个条件达成。
1.2 wait()
-
wait()只有一个参数(相当于第二个参数为true)
void wait( std::unique_lock<std::mutex>& lock )
先解锁之前获得的互斥量mutex,然后阻塞当前的执行线程。把当前线程添加到等待线程列表中,该线程会持续阻塞直到被 ** notify_one()** 唤醒。被唤醒后,该thread会尝试重新获取互斥量mutex,获取到mutex后执行后面的动作。
-
wait()有两个参数
void wait( std::unique_lock<std::mutex>& lock, Predicate pred )
设置了第二个参数 Predicate, 只有当pred为false时,wait才会阻塞当前线程。这情况下,线程被唤醒后,先获取mutex,再次判断pred的值。如果pred为false,则会释放mutex并重新阻塞在wait。
wait() 效果就是把锁释放并阻塞,以便于其他人去获取,不然条件不满足时,一遍遍去询问,太浪费时间。
1.3 notify_one()
随机唤醒一个等待的线程
notify_one() 唤醒一个线程不一定能成功,如果要唤醒的线程不在wait()处等待,将没有唤醒效果。
1.4 notify_all()
唤醒所有等待的线程
#include <iostream>
#include <thread>
#include <mutex>
#include <list>
using namespace std;list<int> test_list;
mutex myMutex1;//创建一个互斥量condition_variable my_cond;//生成一个条件变量对象
void in_list() {for (int num = 0; num < 100000; num++) {{cout << "插入数据:" << num << endl;unique_lock<mutex> myUniLock(myMutex1);//操作事务test_list.push_back(num);my_cond.notify_one();//我们尝试把wait()的线程唤醒,执行完这行,那么out_list()里边的wait就会被唤醒}}
}void out_list() {int command = 0;while (true) {unique_lock<mutex> myUniLock(myMutex1);//如果第二个参数lambda表达式返回值是false,那么wait()将解锁互斥量,并堵塞到本行,my_cond.wait(myUniLock, [=] {//一个lambda就是一个可调用的对象(函数)if (!test_list.empty())return true;return false;});//流程只要走到这里来,这个互斥锁一定是锁着的command= test_list.front();//返回第一个元素,但不检查元素是否存在test_list.pop_front();//移除第一个元素,但不返回myUniLock.unlock();//可以提前解锁,以免锁住太长时间//执行其它非共享数据业务cout << "out_list()执行,取出一个元素" << command << endl;}
}
int main()
{thread in_thread(in_list);thread out_thread(out_list);out_thread.join();in_thread.join();cout << "I love China!" << endl;return 0;
}
2、深入思考
上面的代码可能导致出现一种情况:
因为out_list()与in_list()并不是一对一执行的,所以当程序循环执行很多次以后,可能在test_list中已经有了很多消息,但是,out_list还是被唤醒一次只处理一条数据。这时可以考虑把out_list多执行几次,或者对in_list进行限流。