これは、条件変数を使用することで、ユニプロデューサー/マルチコンシューマー モデルでかなり簡単に行うことができます。これは1 つのアーキテクチャであり、他のアーキテクチャも可能であることを覚えておいてください。
メイン スレッドでは、キュー、ミューテックス、および条件変数を作成し、実行したい数のスレッドを起動するだけです。次のような擬似コードです。
glbQueue = []
glbMutex = new mutex
glbCondVar = new condvar
for i = 1 to 10:
start thread using thrdFn
次のステップは、必要なワークアイテムを (ミューテックスを使用して) キューに追加し、条件変数をキックして、必要に応じてスレッドをウェイクアップすることです。
while workitem = getNextWorkItem():
lock glbMutex
glbQueue.append (workItem)
kick glbCondVar
unlock glbMutex
すべての作業項目が完了したら、キューが空になるのを待ってから、いくつかの番兵項目を投稿してスレッドをシャットダウンし、それらが終了するのを待ってから終了します。
lock glbMutex
while glbQueue is not empty:
kick glbCondVar
unlock glbMutex.
sleep for a bit
lock glbMutex
unlock glbMutex.
for i = 1 to 10:
lock glbMutex
glbQueue.append (endWorkItem)
kick glbCondVar
unlock glbMutex.
wait for any one thread to exit
exit
作業を行うスレッドも比較的単純です。まず、条件変数がキックされるのを待って無限ループで実行されます。そのループ内で、使用可能なワークアイテムがなくなるまで処理し、その後スリープ状態に戻ります。
スレッドが最終作業項目を受け取ると終了し、各スレッドが 1 つの最終項目を取得することが保証されます。
つまり、次のようなものです。
initialise
stillGoing = true
lock glbMutex
while stillGoing:
wait on glbCondVar using glbMutex
while stillGoing and glbQueue is not empty:
extract workItem from glbQueue to thread local storage
unlock glbMutex.
if workItem is endWorkItem:
stillGoing = false
else:
do the work specified by workItem
lock glbMutex
unlock glbMutex
clean up
exit thread
これにより、基本的に、キューでアイテムを処理するスレッドの数を固定でき、キュー自体はミューテックスによって保護されるため、ワーカー スレッドとメイン スレッドの間で競合が発生することはありません。