如何在两个线程之间共享公共资源?

时间:2019-06-07 04:55:33

标签: c++ multithreading c++11

这是我的代码,在这里我试图以分离模式访问两个不同线程中的资源,但无法读取第二个线程中m_dataLoaded的更新值。即使满足条件,它也会继续等待。我不了解其背后的逻辑以及如何实现此目标?

头文件 application.h

#ifndef APPLICATION_H
#define APPLICATION_H

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

class Application
{
public:
    Application();

    bool isDataLoaded();

    void loadData();

    void mainTask();

private:
    bool m_dataLoaded;
    std::condition_variable m_condVar;
    std::mutex m_mutex;
};

#endif // APPLICATION_H

源文件 application.cpp

#include "application.h"

Application::Application()
           : m_dataLoaded(false)
{
}

bool Application::isDataLoaded()
{
     return m_dataLoaded;
}

void Application::loadData()
{
    std::cout << "Inside loadData" << std::endl;

    std::lock_guard<std::mutex> gaurd(m_mutex);

    while(true)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));

        m_dataLoaded = true;

        if(m_dataLoaded)
        {
            m_condVar.notify_one();
        }
    }
}

void Application::mainTask()
{
    std::cout << "Inside mainTask" << std::endl;

    std::unique_lock<std::mutex> u_lock(m_mutex);

    while(true)
    {
        std::cout << "Waiting..." << std::endl;

        m_condVar.wait(u_lock, std::bind(&Application::isDataLoaded, this));

        std::cout << "Start Data Processing: " << std::endl;

        m_dataLoaded = false;
    }

    std::cout << "Break out of the loop" << std::endl;
}

主文件 main.cpp

#include "application.h"

int main()
{
    Application *app = new Application;

    std::thread *thread_1 = new std::thread(&Application::mainTask, app);
    std::thread *thread_2 = new std::thread(&Application::loadData, app);

    thread_2->detach();
    thread_1->detach();

    while(1)
    {
    }

    return 0;
}

对于上面的代码,thread_1一直在等待... 我不明白为什么会这样。 任何帮助将不胜感激...

1 个答案:

答案 0 :(得分:3)

并且在问题的注释部分被rafix07召集-main可能会退出,并在任何线程有机会执行任何操作之前触发程序终止。但这不是您唯一的错误。

您忘记了跳出mainTask中的循环。您的mainTask中的代码陷入了while(true)循环中-即使isDataLoaded()成为真实的表达式之后。

while (true) // <<=== INFINITE LOOP
{
    std::cout << "Waiting..." << std::endl;

    m_condVar.wait(u_lock, std::bind(&Application::isDataLoaded, this));

    std::cout << "Start Data Processing: " << std::this_thread::get_id() << std::endl;

}

我喜欢传统的“循环”方法,因为它类似于先检查条件,然后等待,然后再检查(由于虚假唤醒)的pthreads模式。

while (!isDataLoaded())
{
    std::cout << "Waiting..." << std::endl;

    m_condVar.wait(u_lock);
}

std::cout << "Start Data Processing: " << std::this_thread::get_id() << std::endl;

或者不使用循环,只需使用谓词方法而不使用显式循环:

std::cout << "Waiting..." << std::endl;

m_condVar.wait(u_lock, [this]() {
    return isDataLoaded();
});

std::cout << "Start Data Processing: " << std::this_thread::get_id() << std::endl;

这是您的完成程序,已更正:

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>


class Application
{
public:
    Application();

    bool isDataLoaded();

    void loadData();

    void mainTask();

private:
    bool m_dataLoaded;
    std::condition_variable m_condVar;
    std::mutex m_mutex;
};

Application::Application()
    : m_dataLoaded(false)
{
}

bool Application::isDataLoaded()
{
    return m_dataLoaded;
}

void Application::loadData()
{
    std::cout << "Inside loadData" << std::endl;

    std::this_thread::sleep_for(std::chrono::milliseconds(1000));

    std::lock_guard<std::mutex> gaurd(m_mutex);

    m_dataLoaded = true;

    m_condVar.notify_all();
}

void Application::mainTask()
{
    std::cout << "Inside mainTask" << std::endl;

    std::unique_lock<std::mutex> u_lock(m_mutex);

    while (!isDataLoaded())
    {
        std::cout << "Waiting..." << std::endl;

        m_condVar.wait(u_lock);
    }

    std::cout << "Done Waiting" << std::endl;
}

int main()
{
    Application *app = new Application;

    std::thread *thread_1 = new std::thread(&Application::mainTask, app);
    std::thread *thread_2 = new std::thread(&Application::loadData, app);

    std::cout << "Thread_1 id: " << thread_1->get_id() << std::endl;

    thread_2->detach();
    thread_1->detach();

    while (true)
        std::this_thread::sleep_for(std::chrono::milliseconds(100000));

    return 0;
}