1. std::condition_variable::notify_xxx的时候,如果没有std::condition_variable::wait,通知会被忽略。
2. std::condition_variable::wait(unique_lock& lck, Predicate pred);在调用的时候会先判断pred是否为true,若为true就继续执行,不会执行"把lck解锁并挂起"的任务。等同于while(!pred()) wait(lck);
3. 举例:
下边这种情况,由于在notify在wait之前,所以通知都给忽略了,最后所有的func_pop线程都在等。
虽然wait里边有pred判断函数(这里用lambda表达式),但是由于start=false,所以lck还是会被解锁然后挂起条件变量。如果把start删了,那么就不会卡住,因为压根不会挂起条件变量,直接跳过去了。
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include <list>
using namespace std;
bool start = false;
class test
{
public:
void push(int val);
void push_no(int val);
int pop();
public:
list<int> m_list;
condition_variable m_cond;
mutex m_mutex;
};
void test::push(int val){
unique_lock<mutex> lock(m_mutex);
m_list.push_back(val);
m_cond.notify_all();
}
int test::pop(){
unique_lock<mutex> lock(m_mutex);
m_cond.wait(lock, [&]()-> bool {return !(this->m_list.empty() && start);});
int val = m_list.front();
m_list.pop_front();
return val;
}
void func_push(test& val, int i){
val.push(i);
}
void func_pop(test& val){
printf("%d\n",val.pop());
}
int main(int argc, char* argv[]){
int num = atoi(argv[1]);
list<shared_ptr<thread>> tlist;
test val_;
//先push,也就是先通知
for(int i = 0; i != num ; ++i){
{
shared_ptr<thread> t;
//防止创建线程失败,用try...catch捕获异常
try{
shared_ptr<thread> temp = make_shared<thread>(func_push, ref(val_), i);
t.swap(temp);
}catch(system_error &e){
printf("error : %s\n", e.what());
continue;
}
tlist.push_back(t);
}
}
//先暂停1s,保证func_push执行完毕
sleep(1);
for(int i = 0; i != atoi(argv[1]); ++i){
shared_ptr<thread> t;
try{
shared_ptr<thread> temp = make_shared<thread>(func_pop, ref(val_));
t.swap(temp);
}catch(system_error &e){
printf("error : %s\n", e.what());
continue;
}
tlist.push_back(t);
}
start = true;
return 0;
}
如果先执行func_pop线程,让条件变量处于wait状态再通知,那么func_pop线程就被通知到,而不会被忽略