I've got a function which starts a number of worker threads. Each worker thread is encapsulated by an object, and the destructor of that object will try to join
the thread, i.e calls if (thrd_.joinable()) thrd_.join();
. But it is unknown a priori how much work each worker will have to perform. the managing function assigns work units to the threads using a mutex and a condition variable. If there is no more work to do, a certain flag is set while the mutex is being held, and then all threads blocked on the condition variable are notified so they wake up, notice the changed flag, and shut down.
I want this shutdown to work even if there is an exception in the main thread. In Java I'd use a finally
clause to always set the flag and notify threads at the end of the work processing loop. As C++ doesn't have finally
, I wrote my own replacement:
class FinallyGuard {
private:
std::function<void()> f_;
public:
FinallyGuard(std::function<void()> f) : f_(f) { }
~FinallyGuard() { f_(); }
};
void Manager::manageWork(unsigned NumWorkers) {
// Order matters: destructors are called in reverse order and will
// 1. release the mutex lock so that workers can proceed
// 2. unblock all threads using the finally workalike
// 3. destroy the workers and join their threads
std::forward_list<Worker> workers;
FinallyGuard signalEndGuard([this] {
std::unique_lock<std::mutex> lk(mtx_);
done_ = true;
beginWork_.notify_all();
});
std::unique_lock<std::mutex> lk(mtx_);
for (unsigned i = 0; i != numWorkers; ++i)
workers.emplace_front(this);
while (haveMoreWork()) {
// …
}
}
But I'm clearly thinking in concepts from other languages here. Is there a more C++-like way to achieve this? A solution would either need to execute some code both for normal return from a method and for the case where an exception is thrown, or provide some better mechanism to wake up workers instead of the flag and condition variable combination.