c++ - 终止 worker

标签 c++ multithreading c++11 finally

我有一个启动多个工作线程的函数。每个工作线程都由一个对象封装,该对象的析构函数将尝试加入线程,即调用if (thrd_.joinable()) thrd_.join();。但是,每个 worker 必须完成多少工作是先验未知的。管理功能使用互斥锁和条件变量将工作单元分配给线程。如果没有更多的工作要做,则在持有互斥量的同时设置某个标志,然后通知所有阻塞在条件变量上的线程,以便它们醒来,注意到更改的标志,然后关闭。

即使主线程中出现异常,我也希望此关闭工作。在 Java 中,我会使用 finally 子句来始终设置标志并在工作处理循环结束时通知线程。作为C++ doesn't have 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++ 的方法来实现这一点?解决方案要么需要执行一些代码,既可以从方法正常返回,也可以在抛出异常的情况下执行,或者提供一些更好的机制唤醒工作人员而不是标志和条件变量组合。

最佳答案

C++ 中确实存在 try finally 等价物,尽管核心语言中没有。它被称为 ScopeGuard,最初由 Andrej Alexandrescu 创建,他是 C++ 领域的“摇滚明星”之一。他在 2012 年 C++ 和 Beyond session 上展示了新版本 http://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C

更重要的是这里的代码: https://gist.github.com/KindDragon/4650442

您的示例做的事情几乎相同。如果您希望其他 C++ 程序员理解您的意思,您可能应该将其称为 ScopeGuard 或使用 Alexandrescus 代码(您可能应该将其放入库或公共(public)包含中,它经常被使用)。 C++ 程序员对所有事情都使用 RAII,在我看来,表达意图很重要,

SCOPE_EXIT {
    std::unique_lock<std::mutex> lk(mtx_);
    done_ = true;
    beginWork_.notify_all();
};

在你的情况下。

我工作的地方 ScopeGuard 被认为是很好的风格,并且很好地通过了代码审查。如果您想将其用于商业用途,它也是公共(public)领域。

关于c++ - 终止 worker ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15222502/

相关文章:

c++ - 如果 control-reaches-end-of-body 返回 nullopt,什么会中断?

c++ - cbegin/cend 是否不足以用于基于范围的 for 循环?

c++ - 将 map 与枚举类成员一起使用

c++ - 用不同的 IDE 编译,但只有一个可以工作!

Python 多线程 - 使用 While 语句运行时未释放内存

c++ - QtConcurrent 在 App 即将退出时等待完成

使用 std::string::c_str() 时的 C++11 类型转换 heisenbug

c - 如何查询多个 pthread(子线程)以了解哪一个线程终止

C++ Pimpl Idiom 使用预先存在的类

c++ - 为什么 C++11 会从 std::vector 的填充构造函数原型(prototype)中移除默认值?