本节讨论在多线程环境下的事件处理。
有时,线程需要等待某事件发生,比如一个条件变为true,或者某任务被另一个线程完成。
例如,我们创建一个基于网络的应用程序,处理如下的任务:
1、与处理器进行一些握手操作;
2、从xml文件load数据;
3、处理从xml文件load的数据.
可以发现,任务1不依赖其他的任务,而任务3则依赖于任务2,这意味着任务1和任务2可以由不同的线程并行运行,以提升程序性能。
因此,让我们将其分解成一个多线程的应用程序
现在,它包含2个线程,线程1的任务是:
·与服务器进行握手操作
·等待线程2从xml获取的数据
·处理从xml获取的数据
线程2的任务是:
·从xml获取数据
·通知另一个线程,即等待消息
在上图中,线程1处理一些操作,然后等待event发生,这event是 “数据是否成功获取”,一旦线程1收到该event,那么它将对数据进行处理。
当线程1忙于处理握手机制时,线程2并行地获取数据。
当线程2成功从xml处获取数据后,它将通过对event发信号来通知线程1。
当event发出信号时,线程1将继续处理数据。
实现方式
选项1:
创建一个默认为false的boolean型全局变量,在线程2中将其设为true,线程1将会循环检测其值,一旦该值被设为true,线程1将会继续处理数据,
由于它是一个由两个线程共享的全局变量,需要使用mutex锁进行同步。
代码如下:
#include <iostream>
#include <thread>
#include <mutex>
class Application
{
std::mutex m_mutex;
bool m_bDataLoaded;
public:
Application(){
m_bDataLoaded = false;
}
void loadData(){
//使该线程sleep 1秒
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout<<"Load Dada from Xml"<<std::endl;
//锁定数据
std::lock_guard<std::mutex> guard(m_mutex);
//flag设为true,表明数据已加载
m_bDataLoaded = true;
}
void mainTask(){
std::cout<<"Do some Handshaking"<<std::endl;
//获得锁
m_mutex.lock();
//检测flag是否设为true
while (m_bDataLoaded != true) {
//释放锁
m_mutex.unlock();
//sleep 100ms
std::this_thread::sleep_for(std::chrono::milliseconds(100));
//获取锁
m_mutex.lock();
}
m_mutex.unlock();
//处理加载的数据
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;
}
输出:
Do some Handshaking
Load Dada from Xml
Do Processing On loaded Data
该方法存在以下缺陷:
为了检测变量,线程将会持续获取-释放锁,这样会消耗CPU周期并且使线程1变慢,因为它需要获取相同的锁来更新bool变量。
因此,显然我们需要一个更好的实现机制,如某种方式,线程1可以通过等待event信号来阻塞,另一个线程可以通知该event并使线程1继续。这将会有相同的CPU周期,并有更好的性能。
选项2:
我们可以使用条件变量来实现,条件变量是一种用于在2个线程之间进行信令的事件,一个线程可以等待它得到信号,其他的线程可以给它发信号。
下一节会详细说明这个条件变量,并使用条件变量来解决问题。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)