11

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.

Laser Focus
  • 123
  • 6

1 Answers1

11

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();
Community
  • 1
  • 1
Revolver_Ocelot
  • 8,609
  • 3
  • 30
  • 48
  • 2
    There are still other problems: If cv.notify_one is called before cv.wait is running the notification will be missed. In the presented code it most probably will. The variable 'started' is set to true by the first worker_thread and remains in this state. – CAF Apr 01 '17 at 16:28
  • @CAF I forgot to write started = false at end of while loop, have updated the code. But I do not understand how to solve missing notification problem, I cannot wait random amount of time since start event can take any amount of time.. – Laser Focus Apr 01 '17 at 20:34
  • @Laser Focus: If you switch the std::async and the std::unique_lock statements before the cv.wait, the wait will definitly happen before the notify_one. – CAF Apr 02 '17 at 09:16
  • @Laser Focus: The wait on the condition variable releases the lock making the thread run... – CAF Apr 03 '17 at 17:30