Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ condition variable notification not working as expected

I'm trying to launch new threads as soon as work in previous worker_thread has started, but maybe ended or not. I've replaced started and ended work with time delays. My code is:

#include <iostream>
#include <string>
#include <mutex>
#include <condition_variable>
#include <future>
#include <atomic>
#include <chrono>
#include <thread>

std::mutex m;
std::condition_variable cv;
bool started = false;

void worker_thread()
{
    std::unique_lock<std::mutex> lk(m);

    static std::atomic<int> count(1);
    std::this_thread::sleep_for(std::chrono::milliseconds{(count % 5) * 100});
    std::cerr << "Start Worker thread: " << count << "\n";

    started = true;
    lk.unlock();
    cv.notify_one();

    std::this_thread::sleep_for(std::chrono::milliseconds{3000});
    std::cerr << "Exit Worker thread: " << count << "\n";
    ++count;
}

int main()
{
    while(1) {
        std::async(std::launch::async, worker_thread);
        std::unique_lock<std::mutex> lk(m);
        cv.wait(lk, []{return started;});
        started = false;
    }
}

The output looks like that:

Start Worker thread: 1
Exit Worker thread: 1
Start Worker thread: 2
Exit Worker thread: 2
Start Worker thread: 3
Exit Worker thread: 3
Start Worker thread: 4
Exit Worker thread: 4
Start Worker thread: 5
Exit Worker thread: 5

which isn't the behavior I wanted. What I wanted was something like (not exactly) this:

Start Worker thread: 1
Start Worker thread: 2
Start Worker thread: 3
Start Worker thread: 4
Exit Worker thread: 1
Exit Worker thread: 3
Exit Worker thread: 4
Exit Worker thread: 2
Start Worker thread: 5
Exit Worker thread: 5

Currently the next thread is only started when work is finished in previous thread. But I want to start next thread as soon as work is started in previous thread and not wait for it's end, only wait for start.

like image 707
Laser Focus Avatar asked Apr 01 '17 12:04

Laser Focus


1 Answers

std::async returns a std::future holding result of function execution. In your case, it is a temporary object which is immideatly destroyed. The documentation for std::future says:

these actions will not block for the shared state to become ready, except that it may block if all of the following are true:

✔ the shared state was created by a call to std::async

✔ the shared state is not yet ready

✔ this was the last reference to the shared state

All of those are true, so destruction of that future will block until worker function will finish executing.

You can create detached thread to avoid this problem:

std::thread(worker_thread).detach();
like image 79
Revolver_Ocelot Avatar answered Nov 17 '22 05:11

Revolver_Ocelot