前面提到了线程,那么肯定就要说到条件变量。
条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待
条件变量的条件成立而挂起;另一个线程使条件成立(给出条件成立信号)。为了防止竞争,条件变
量的使用总是和一个互斥量结合在一起。
头文件
condition_variable
condition_variable_any
相同点:两者都能与std::mutex一起使用。
不同点:前者仅限于与 std::mutex 一起工作,而后者可以和任何满足最低标准的互斥量一
起工作,从而加上了_any的后缀。condition_variable_any会产生额外的开销。
一般只推荐使用condition_variable。除非对灵活性有硬性要求,才会考虑condition_variable_any。
条件变量的构造函数:
std::condition_variable::condition_variableconstructor: condition_variable(); //默认构造函数无参 condition_variable(const condition_variable&) = delete; //默认构造函数无参
条件变量的wait函数:
void wait( std::unique_lock<std::mutex>& lock );//Predicate是lambda表达式。template< class Predicate >void wait( std::unique_lock<std::mutex>& lock, Predicate pred );//以上二者都被notify_one())或notify_broadcast()唤醒,但是//第二种方式是唤醒后也要满足Predicate的条件。//如果不满足条件,继续解锁互斥量,然后让线程处于阻塞或等待状态。//第二种等价于while (!pred()){ wait(lock);}
例子:
#include #include #include #include #include std::mutex m;std::condition_variable cv;std::string data;bool ready = false;bool processed = false; void worker_thread(){ // Wait until main() sends data std::unique_lock<std::mutex> lk(m); //子进程的中wait函数对互斥量进行解锁,同时线程进入阻塞或者等待状态。 cv.wait(lk, []{return ready;}); // after the wait, we own the lock. std::cout << "Worker thread is processing data\n"; data += " after processing"; // Send data back to main() processed = true; std::cout << "Worker thread signals data processing completed\n"; // Manual unlocking is done before notifying, to avoid waking up // the waiting thread only to block again (see notify_one for details) lk.unlock(); cv.notify_one();} int main(){ std::thread worker(worker_thread); data = "Example data"; // send data to the worker thread { //主线程堵塞在这里,等待子线程的wait()函数释放互斥量。 std::lock_guard<std::mutex> lk(m); ready = true; std::cout << "main() signals data ready for processing\n"; } cv.notify_one(); // wait for the worker { std::unique_lock<std::mutex> lk(m); cv.wait(lk, []{return processed;}); } std::cout << "Back in main(), data = " << data << '\n'; worker.join();}
在以上的代码中,子线程先对互斥量进行加锁,在main()函数中,主线程堵塞在对互斥量的加锁这里。子进程的中wait函数对互斥量进行解锁,同时线程进入阻塞或者等待状态。
通知wait()取消对线程的阻塞有:
notify_one()
通知第一个进入阻塞或者等待的线程。
notify_broadcast()
通知全部进入阻塞或者等待的线程。
spurious wakeups(虚假唤醒)
用于多线程竞争条件下,具体含义去参考官方文档。我说一下形象的意思就是你妈同时通知你爸和你去做饭,做饭只需要一个人做即可, 当你去准备做饭时,你爸已经在做饭了,所以你就相当于被虚假唤醒了。
顺便说一下Linux环境下的条件变量, 其实C++11标准也就是对condition_variable的一个封装。
以下为Linux环境下的函数:
pthread_cond_init();pthread_cond_destroy();pthread_cond_wait()pthread_cond_signal();pthread_cond_broadcast();
这些会另外写一篇文章。