终止工人

时间:2013-03-05 11:21:55

标签: c++ multithreading c++11 finally

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

即使主线程中存在异常,我希望此关闭也能正常工作。在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 ++的方法来实现这一目标?解决方案要么需要执行一些代码,以便从方法中正常返回,也需要执行抛出异常的情况,或者提供更好的机制唤醒工人而不是旗帜和条件变量组合。

2 个答案:

答案 0 :(得分:1)

尽管不是在核心语言中,但在C ++中确实存在等效的尝试。它被称为ScopeGuard,最初由Andrej Alexandrescu创造,他是“摇滚明星”中的一员。 C ++字段。在这里,他将在C ++和Beyond conference 2012 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代码(您可能将其置于库中或常用包含,经常使用)。 C ++程序员使用RAII作为一切,在我看来,表达意图非常重要,

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

在你的情况下。

我工作的地方ScopeGuard被认为是好的风格,并且通过代码审查就好了。如果您想在商业上使用它,它也是公共领域。

答案 1 :(得分:0)

C ++的方式是使用名为RAII的东西。您使用的事实是始终调用析构函数以确保始终运行某些代码。