Search code examples
c++c++11boostboost-threadproducer-consumer

Notify Waiters at Thread Exit


Consider the following example. Suppose you have one producer and N consumers waiting for data. You want to notify the consumers not only whenever the data is ready but also when the producer terminates for some reason (an error, or an interruption point). In the latter case, the readers should terminate as well.

// Globals
boost::shared_future<void> future;
boost::condition_variable_any cv;

// Producer
auto producer = [&](){
    boost::this_thread::at_thread_exit([&cv] () { cv.notify_all(); });
    while (true) {
            boost::this_thread::interruption_point(); // might throw
            // ...
            cv.notify_all();
    }
};   
boost::packaged_task<void> pkg{producer};
future = pkg.get_future();
thread = boost::thread{std::move(pkg)}; // start

// Reader
while (true) {
        // ...
        // will the future be ready after the producer has been interrupted?
        cv.wait(lock_, [&ready, &future]() { return ready || future.is_ready(); });
        if (future.is_ready()) {
            future.get(); // throw, whatever has been thrown by the producer
            return;
        }
        // consume, etc...
}

Is the above guaranteed to work? I would like to avoid to introduce a boolean flag or - better - another new promise/future pair to notify and make the readers know why the producer has exited.

Basically I am not sure if the future associated with the packaged_task can be considered ready when the readers are notified by the function registered with boost::this_thread::at_thread_exit. This would simplify the code in my case (instead of passing a new promise to the producer thread). If you have better ideas, please let me know.


Solution

  • Yes this will work.

    In particular

    Basically I am not sure if the future associated with the packaged_task can be considered ready when the readers are notified by the function registered with boost::this_thread::at_thread_exit

    They can. The packaged_task is the thread function. By the time the thread_proxy implementation from Boost Thread executes the tls_destructor (which includes the at_thread_exit hook), the packaged_task has already returned and the promise has been fulfilled -> the shared future is ready.