C++ Wait for bool to change in another class

1

I have a Program class and a Browser class.

Inside my Program::Run(), I launch the Browser to start in a separate thread. However, before I continue with my Run() method, I want to wait for a certain part of the Browser to initialize, thus I need to check if a variable has been set in the browser object.

Used as the thread for the browser

int Program::_Thread_UI_Run() {
  ...
  return Browser->Run();
}

I am using async to run the browser thread and retrieve its return value when it is finished.

int Program::Start() {
    std::unique_lock<std::mutex> lck(mtx);
    auto t1 = std::async(&Program::_Thread_Browser_Run, this);
    cv.wait(lck);
     ... when wait is released, do stuff

    // Thread finishes and returns an exit code for the program
    auto res1 = f1.get();

// return res1 as exit code.
}

Browser.cpp class

int Browser::Run()
{
    // Initialize many things
    ...

    m_Running = true; 
    cv.notify_all(); // Notify the waiter back in Program

    // This will run for as long as the program is running
    while (m_Running)
    {
      ... browser window message loop
    }
    return exit_code;
}

I have problems setting this up. The program is crashing :/ Do I pass the mutex variable to everything using it? Or just recreate it in every function body? What about the conditional_variable?

With the current setup the program crashes: The exception Breakpoint A breakpoint has been reached. (0x80000003) occured in the application at location 0x107d07d6.

Hints and help is appreciated

Edit: Updated code to match new suggestions

In browser's .h file: std::atomic_bool m_Running;

int Browser::Run(std::condition_variable& cv)
{
    int exit_code = 0;
    // Set up, and attain the desired state:
    ...
    m_Running = true;
    cv.notify_all();
    while (m_Running)
    {
        // Process things etc
    }
    return exit_code;
}

int Program::Start()
{
    std::mutex m;
    std::condition_variable cv;

    auto t1 = std::async(&Program::_Thread_UI_Run, this, std::ref(cv));
    std::unique_lock<std::mutex> lock(m);
    cv.wait(lock);


    .... stuff


    return t1.get();
}

I have a logger that helps me keep track of how the program is running. By placing logger calls in crucial places in the code I was able to confirm that the program waits appropiately before continuing. However I still get prompted with

The exception Breakpoint A breakpoint has been reached. (0x80000003) occured in the application at location 0x107d07d6.

By commenting out //cv.wait(lock); the program resumes to work.. :/ Why would waiting making it crash like that?

c++
multithreading
asked on Stack Overflow Jan 6, 2016 by Mads M • edited Jan 7, 2016 by Mads M

1 Answer

3

You definitely want to use std::condition_variable. It allows you to signal other threads once an operation has complete, so in your case, once the bool has been set:

Browser::Run()
{
    // Set some things up, make sure everything is okay:
    ...
    m_Running = true; // Now the thread is, by our standards, running*
    // Let other threads know:
    cv.notify_all();
    // Continue to process thread:
    while (m_Running)
    {
    }
}

And then in your main / other thread:

auto t1 = std::async(&Program::_Thread_Browser_Run, this);
// Wait until we know the thread is actually running. This will pause this thread indefinitely until the condition_variable signals.
cv.wait();

You should pass the std::condition_variable into any function using it, so your code would look more like:

int Browser::Run(std::condition_variable& cv)
{
    int exit_code = 0;
    // Set up, and attain the desired state:
    ...
    m_Running = true;
    cv.notify_all();
    while (m_Running)
    {
        // Process things etc
    }
    return exit_code;
}

int Program::Start()
{
    std::mutex m;
    std::condition_variable cv;
    auto t1 = std::async(&Program::_Thread_UI_Run, this, std::ref(cv));
    std::unique_lock<std::mutex> lock(m);
    // Wait until the browser is in the desired state
    cv.wait(lock);
    // The thread has signalled. At this point, Browser::m_Running = true
    // Wait for the browser to exit, and then propagate its exit code
    return t1.get();
}

@Richard Hodges raises an excellent point in the comments, which I overlooked: m_Running needs to be std::atomic (or have locking around its use) otherwise both threads may try to use it once. std::condition_variable is thread-safe and doesn't require locking around it.

*Of course the thread is running at that point, I just mean it's in the state you desire

answered on Stack Overflow Jan 6, 2016 by Tas • edited Jan 7, 2016 by Tas

User contributions licensed under CC BY-SA 3.0