条件变量
条件变量是一种用于在2个线程之间进行信令的事件,一个线程可以等待它得到信号,其他的线程可以给它发信号。
在c++11中,条件变量需要头文件:
#include <condition_variable>
条件变量的主要成员函数是:
Wait()
它使得当前线程阻塞,直到条件变量得到信号或发生虚假唤醒;
它原子性地释放附加的mutex,阻塞当前线程,并将其添加到等待当前条件变量对象的线程列表中,当某线程在同样的条件变量上调用notify_one() 或者 notify_all(),线程将被解除阻塞;
这种行为也可能是虚假的,因此,解除阻塞后,需要再次检查条件;
一个回调函数会传给该函数,调用它来检查其是否是虚假调用,还是确实满足了真实条件;
当线程解除阻塞后,wait()函数获取mutex锁,并检查条件是否满足,如果条件不满足,则再次原子性地释放附加的mutex,阻塞当前线程,并将其添加到等待当前条件变量对象的线程列表中。
notify_one()
如果所有线程都在等待相同的条件变量对象,那么notify_one会取消阻塞其中一个等待线程。
notify_all()
如果所有线程都在等待相同的条件变量对象,那么notify_all会取消阻塞所有的等待线程。
如何处理第六节讨论的带有条件变量的多线程情景呢?
因此,让我们将其分解成一个多线程的应用程序。
线程1的任务是:
实现代码如下:
条件变量是一种用于在2个线程之间进行信令的事件,一个线程可以等待它得到信号,其他的线程可以给它发信号。
在c++11中,条件变量需要头文件:
#include <condition_variable>
同时,条件变量还需要一个mutex锁
条件变量实际上是如何运作的
·线程1调用等待条件变量,内部获取mutex互斥锁并检查是否满足条件; ·如果没有,则释放锁,并等待条件变量得到发出的信号(线程被阻塞),条件变量的wait()函数以原子方式提供这两个操作; ·另一个线程,如线程2,当满足条件时,向条件变量发信号; ·一旦线程1正等待其恢复的条件变量发出信号,线程1便获取互斥锁,并检查与条件变量相关关联的条件是否满足,或者是否是一个上级调用,如果多个线程正在等待,那么 notify_one将只解锁一个线程; ·如果是一个上级调用,那么它再次调用wait()函数。
条件变量的主要成员函数是:
Wait()
它使得当前线程阻塞,直到条件变量得到信号或发生虚假唤醒;
它原子性地释放附加的mutex,阻塞当前线程,并将其添加到等待当前条件变量对象的线程列表中,当某线程在同样的条件变量上调用notify_one() 或者 notify_all(),线程将被解除阻塞;
这种行为也可能是虚假的,因此,解除阻塞后,需要再次检查条件;
一个回调函数会传给该函数,调用它来检查其是否是虚假调用,还是确实满足了真实条件;
当线程解除阻塞后,wait()函数获取mutex锁,并检查条件是否满足,如果条件不满足,则再次原子性地释放附加的mutex,阻塞当前线程,并将其添加到等待当前条件变量对象的线程列表中。
notify_one()
如果所有线程都在等待相同的条件变量对象,那么notify_one会取消阻塞其中一个等待线程。
notify_all()
如果所有线程都在等待相同的条件变量对象,那么notify_all会取消阻塞所有的等待线程。
如何处理第六节讨论的带有条件变量的多线程情景呢?
c++11多线程编程(六):事件处理 (这节中,我们没有用事件处理来解决问题)
问题场景
我们创建一个基于网络的应用程序,处理如下的任务:
1、与处理器进行一些握手操作; 2、从xml文件load数据; 3、处理从xml文件load的数据.可以发现,任务1不依赖其他的任务,而任务3则依赖于任务2,这意味着任务1和任务2可以由不同的线程并行运行,以提升程序性能。
因此,让我们将其分解成一个多线程的应用程序。
线程1的任务是:
·与服务器进行握手操作 ·等待线程2从xml获取的数据 ·处理从xml获取的数据线程2的任务是:
·从xml获取数据 ·通知另一个线程,即等待消息
实现代码如下:
#include <iostream>
#include <thread>
#include <functional>
#include <mutex>
#include <condition_variable>
using namespace std::placeholders;
class Application {
std::mutex m_mutex;
std::condition_variable m_condVar;
bool m_bDataLoaded;
public:
Application() {
m_bDataLoaded = false;
}
void loadData() {
//使该线程sleep 1秒
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "Loading Data from XML" << std::endl;
//锁定数据
std::lock_guard<std::mutex> guard(m_mutex);
//flag设为true,表明数据已加载
m_bDataLoaded = true;
//通知条件变量
m_condVar.notify_one();
}
bool isDataLoaded() {
return m_bDataLoaded;
}
void mainTask() {
std::cout << "Do some handshaking" << std::endl;
//获取锁
std::unique_lock<std::mutex> mlock(m_mutex);
//开始等待条件变量得到信号
//wait()将在内部释放锁,并使线程阻塞
//一旦条件变量发出信号,则恢复线程并再次获取锁
//然后检测条件是否满足,如果条件满足,则继续,否则再次进入wait
m_condVar.wait(mlock, std::bind(&Application::isDataLoaded, this));
std::cout << "Do Processing On loaded Data" << std::endl;
}
};
int main() {
Application app;
std::thread thread_1(&Application::mainTask, &app);
std::thread thread_2(&Application::loadData, &app);
thread_2.join();
thread_1.join();
return 0;
}