2

Here is my piece of code, where I am trying to access a resource in two different threads in a detach mode, but I am not able read the update value of m_dataLoaded in second thread. It continues to wait even if the condition is met. I don't understand the logic behind this and how can I achieve this??

Header file 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

Source file 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 file 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;
}

For above piece of code thread_1 keeps on waiting... I don't understand why this happens. Any help would be appreciated...

  • ... your application ends before you can see any results. Threads were started, detach was called, so `main` ends immediately. – rafix07 Jun 07 '19 at 05:09
  • thank you @rafix07, you were right. I put a infinite loop at the end of main and I can see the print statements – Nikhil Singh Jun 07 '19 at 05:30
  • `std::thread::join` iso detach would make more sense. Why do you [new all classes?](https://stackoverflow.com/a/53898150/2466431) – JVApen Jun 07 '19 at 07:24

1 Answers1

3

And was called out by rafix07 in the comments section of your question - main is likely exiting and triggering program termination before either thread has a chance to do anything. But that's not your only bug.

You are forgetting to break out of the loop in mainTask. Your code in mainTask is stuck in a while(true) loop - even after isDataLoaded() becomes a true expression.

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;

}

Traditional "loop" approach that I prefer because it resembles the pthreads pattern of checking the condition first, then waiting, and then checking again (because of spurious wakeups).

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

    m_condVar.wait(u_lock);
}

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

Or without using a loop, just use the predicate approach without an explicit loop:

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;

Here's your comlete program modified with corrections:

#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;
}
selbie
  • 100,020
  • 15
  • 103
  • 173
  • Thank you for the reply. However, I have edited my code and I think I have entered into a deadlock. But I don't know how to fix it... – Nikhil Singh Jun 07 '19 at 08:44
  • Perhaps that `while(1) {}` loop you have in the main thread is starving the threads. I've appended the complete program with my updates. Works for me. – selbie Jun 07 '19 at 08:59