C++11 多线程 - Part 6:事件处理的需要

翻译自:https://thispointer.com//c11-multithreading-part-6-need-of-event-handling/

在本文中,我们将讨论多线程中事件处理的需要。

有时一个线程需要等待一个事件发生,比如一个条件变为真,或者一个任务由另一个线程完成。

例如,假设我们正在构建一个基于网络的应用程序。此应用程序执行以下任务,

1. 与服务器进行交互。
2. 从XML文件加载数据。
3. 对从XML加载的数据进行处理。

我们可以看到,任务1不依赖于任何其他任务,但任务3依赖于任务2。因此,它意味着任务1和任务2可以由不同的线程并行运行,以提高应用程序的性能。
所以,让我们把它分解成一个多线程应用程序,
现在,它包括两个线程,
线程1的职责是,

* 与服务器进行交互。
* 等待线程2从XML加载数据
* 对从XML加载的数据进行处理。

线程2的职责是,

* 从XML加载数据
* 通知另一个线程,即等待消息。

在上面,线程1执行一些操作,然后等待事件/条件发生。 这里的事件或条件是数据是否成功加载。

线程1收到该事件后,便会对数据执行一些处理。
当线程1忙于执行Hand Shake机制时,线程2并行加载数据。
当线程2成功从XML加载数据后,它会通过发信号通知该事件来通知线程1。
现在,当发出事件或条件信号时,线程1将继续处理数据。

使它成为多线程有什么好处?
当线程1忙于某种handshaking机制时,线程2将从XML并行加载数据。 因此,它将提高应用程序的性能。

现在,如何实现这一目标,

Option 1:

将布尔全局变量的默认值设为false。 在线程2中将其值设为true,线程1将继续在循环中检查其值,并且一旦变为true,线程1将继续处理数据。 但是,由于这是两个线程共享的全局变量,因此需要与互斥锁同步。 让我们看看它的代码,

#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;
}

/*输出结果:
Do Some Handshaking
Loading Data from XML
Do Processing On loaded Data
*/

它有下面的一些优势:

线程将持续获取该锁并释放它只是为了检查该值,因此它将消耗CPU周期,并使线程1变慢,因为它需要获取相同的锁来更新bool标志。
因此,显然,我们需要一种更好的机制来实现这一目标,例如,如果某种程度上线程1可以通过等待某个事件被信号通知而阻塞,而另一个线程可以通过该信号通知该事件并使线程1继续运行,就可以了。 这样可以节省许多CPU周期并提供更好的性能。 但是问题是如何实现这一目标?
我们将在选项2中看到答案。

Option 2:

我们可以使用条件变量来实现。
条件变量是一种用于在两个线程之间进行信号传递的事件。 一个线程可以等待它发出信号,而另一个线程可以发出信号。
请查看下一篇文章,以获取此多线程系列中的条件变量的详细说明以及使用条件变量解决此问题的方法。
posted on 2020-04-22 11:59  JJ_S  阅读(372)  评论(0编辑  收藏  举报