我有一个启动多个工作线程的函数。每个工作线程都被一个对象封装,该对象的析构函数会尝试join
对该线程进行调用,即调用if (thrd_.joinable()) thrd_.join();
。但是每个工人必须完成多少工作是先验未知的。管理功能使用互斥锁和条件变量将工作单元分配给线程。如果没有更多工作要做,则在持有互斥锁时设置某个标志,然后通知所有在条件变量上阻塞的线程,以便它们醒来,注意更改的标志,然后关闭。
即使主线程中存在异常,我也希望此关闭工作。在 Java 中,我会使用一个finally
子句来始终设置标志并在工作处理循环结束时通知线程。由于C++ 没有finally
,我编写了自己的替换:
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()) {
// …
}
}
但我显然在这里考虑其他语言的概念。有没有更类似于 C++ 的方法来实现这一点?一个解决方案要么需要执行一些代码来从方法正常返回和抛出异常的情况,要么提供一些更好的机制来唤醒工作人员,而不是标志和条件变量的组合。