Threadpool クラスがあり、このクラスには wait() メソッドがあります。これで、クラスは N 個のスレッドを作成できるようになり、スレッドが作成されると、そのハンドルがコンテナーに挿入されます。wait() 関数を実装するために使用した古典的な方法は、コンテナーをトラバースし、次のように単一のハンドルを待機することです。 :
thread_handle_iterator th = get_first_thread_handle_iterator();
thread_handle_iterator th2 = get_last_thread_handle_iterator();
while (th != th2)
{
joint(*th);
++th;
}
そして、これは完全に機能します。ここで、このループを使用する代わりに、すべてのスレッドの実行が開始されたときにアトミック カウンターをインクリメントし、スレッドの実行が終了したときにアトミック カウンターをデクリメントすることができます。count==0 [最後のスレッドが終了中] の場合、イベント [または posix の条件変数] が発生します。このような:
int
thread_entrypoint(Threadpool * p)
{
int result;
p->atomic_thread_count.add();
result = p->getRunnable()->run(); // execute the thread code.
if (p->atomic_thread_count.fetchAndAdd(-1) == 1) // this is the last thread!
{
p->event.signal(); // fires the event/condition variable
}
return result; // the thread returns the result and exits.
}
したがって、基本的にこの方法では、わずらわしいコンテナがなく、スレッドを作成するときにすべてのスレッドを切り離すことができます。これにより、コードが大幅に簡素化されます。次に、Threadpool のスレッドが切り離されていても、呼び出すだけで完了を待つことができます。Threapool::wait() { event.wait(); }
さらに、グローバル アトミック カウンターを追加できるという利点があるため、次のように、すべてのThreadpool インスタンスによって作成されたすべてのスレッドを待機できます。
AtomicInt global_threads_count;
WaitEvent global_all_threads_exited_event;
int
thread_entrypoint(Threadpool * p)
{
int result;
p->atomic_thread_count.add();
global_threads_count.add();
result = p->getRunnable()->run(); // execute the thread code.
if (p->atomic_thread_count.fetchAndAdd(-1) == 1) // this is the last thread!
{
p->event.signal(); // fires the event/condition variable
}
if (global_threads_count.fetchAndAdd(-1) == 1) // this is the last thread of *ALL* threads!
{
global_all_threads_exited_event.signal(); // fires the event/condition variable
}
return result; // the thread returns the result and exits.
}
呼び出すだけで、すべてのスレッドの完了を待つことができますThreapool::waitForAllThreads() { global_all_threads_exited_event.wait(); }
-- これは、信頼性が高く、高速で効果的な設計になるでしょうか?