一、condition_variable
多线程编程中,常会涉及生产者线程与消费者线程同步问题。c++新标准库(boost)中condition_variable比使用mutex更精确的控制线程执行。简单说就是其中一个线程会及时通知其它线程,已经把数据处理好了。等待中的线程得到“通知”被唤醒来处理数据。
二、示例代码
通过以下代码来说明其工作方式。
#include <QtCore/QCoreApplication>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
const int count = 110;
std::mutex g_mutex;
std::condition_variable g_wait_condition;
int value = 0;
bool volatile b_yield = false;
void wait_thread(int n)
{
std::cout << "wait thread id: " << std::this_thread::get_id() << std::endl;
for (int i = 0; i < n; ++i) {
std::unique_lock<std::mutex> lock(g_mutex);
g_wait_condition.wait(lock, []() {return b_yield; });
std::cout << "count: " << i+1 <<
" custom thread print: value= " << value << std::endl;
b_yield = false;
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
std::thread sub_thread(wait_thread, count);
std::cout << "main thread id: " << std::this_thread::get_id() << std::endl;
for (int i = 1; i <= count; i++) {
while (b_yield)
std::this_thread::yield();
std::unique_lock<std::mutex> lock(g_mutex); //[1]
value = i;
if (value % 2 == 0) {
b_yield = true;
g_wait_condition.notify_one();
} else {
std::cout << "main print: value= " << value << std::endl;
}
}
sub_thread.join();
return a.exec();
}
1>先来明确定义的几个变量用意:
value:P、C两线程要读/写的临界资源。
g_mutex: P、C两线程同步互斥量。通过加锁mutex来保证只有一个线程可以访问value。
g_wait_condition:
b_yield: bool 值,等待条件
2>P线程(main() 所在,它负责累加value,当value为2的倍数时唤醒C线程)
P线程首先要知道被唤醒C线程是否已经处理完自己最近一次“生产”的数据([0]所示),否则应该放弃执行权。在”生产“下一个数据时首先进行对互斥量上锁std::unique_lock<std::mutex> lock(g_mutex);([1]所示)上锁成功便可以写临界资源value。假如这个数是2的倍数。将b_yileld置为true。同时唤醒一个等待(阻塞)中的线程。
3> C 线程(wait_thread(int n)所在,主要逻辑是输出value为2的倍数时的值)
在访问value时也要进行加锁处理,假如加锁失败那是因为P线程在写value,它会被阻塞。
g_wait_condition.wait(lock, []() {return b_yield; }); //[3] wait() 函数要检查等待条件是否满足,如果满足则返回,也就是说函数 继续执行,做其数据处理。假如不满足将解锁互斥量,同时使得线程阻塞。一旦有线程对同一condition_variable调用 notify_one()该线程”得到通知“立马”苏醒“。做数据处理。
它将b_yileld 置为false。以便消费者线程可以准备下一个数据。
【注】在多线程中使用condition_variable我们更应该做到消费者线程先执行,以便让其先进入”wait“状态。