在这个文章中 我们将讨论多线程中事件处理的必要性
有时候 线程需要等待某件事情发生 比如条件为真或者是任务通过另外一个线程被完成了
比如
假设我们正在构建一个基于网络的应用程序。此应用程序执行以下任务,
正如我们所见,Task 1 不依赖于任何其他 Task,而 Task 3 依赖于 Task 2。因此,这意味着 Task 1 和 Task 2 可以由不同的线程并行运行,以提高应用程序的性能。
所以,让我们把它分解成一个多线程应用程序,
现在,它包括两个线程,
线程 1 的职责是,
线程 2 的职责是,
在上面,线程 1 执行一些操作,然后等待事件/条件发生。这里的事件或条件是,
数据加载成功。
一旦线程 1 接收到该事件,它就会对数据执行一些处理。
线程 2,当线程 1 忙于做握手机制时并行加载数据。
当线程 2 成功地从 XML 加载数据时,它然后通过向该事件发出信号通知线程 1。
现在,当事件或条件发出信号时,线程 1 将继续处理数据。
使它成为多线程有什么好处?
当线程 1 忙于某种握手机制时,线程 2 将从 XML 并行加载数据。因此,它将提高应用程序的性能。
实现方式:
实现方式
第一种
创建一个默认为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() { // Make This Thread sleep for 1 Second std::this_thread::sleep_for(std::chrono::milliseconds(1000)); std::cout<<"Loading Data from XML"<<std::endl; // Lock The Data structure std::lock_guard<std::mutex> guard(m_mutex); // Set the flag to true, means data is loaded m_bDataLoaded = true; } void mainTask() { std::cout<<"Do Some Handshaking"<<std::endl; // Acquire the Lock m_mutex.lock(); // Check if flag is set to true or not while(m_bDataLoaded != true) { // Release the lock m_mutex.unlock(); //sleep for 100 milli seconds std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Acquire the lock m_mutex.lock(); } // Release the lock m_mutex.unlock(); //Doc processing on loaded Data 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; }
该方法存在以下缺陷:
为了检测变量,线程将会持续获取-释放锁,这样会消耗CPU周期并且使线程1变慢,因为它需要获取相同的锁来更新bool变量。
因此,显然我们需要一个更好的实现机制,如某种方式,线程1可以通过等待event信号来阻塞,另一个线程可以通知该event并使线程1继续。这将会有相同的CPU周期,并有更好的性能。
第二种
我们可以使用条件变量来实现,条件变量是一种用于在2个线程之间进行信令的事件,一个线程可以等待它得到信号,其他的线程可以给它发信号。
下一节会详细说明这个条件变量,并使用条件变量来解决问题。