多数のワーカー スレッドを開始する関数があります。各ワーカー スレッドはオブジェクトによってカプセル化されており、そのオブジェクトのデストラクタが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++のような方法はありますか? 解決策としては、メソッドからの通常の戻りと例外がスローされた場合の両方で何らかのコードを実行するか、フラグと条件変数の組み合わせの代わりにワーカーをウェイクアップするためのより良いメカニズムを提供する必要があります。