これは、 Semaphoreを使用して簡単に実行できます。
アイデアは、最大数 N のセマフォを作成することです。ここで、N は許可するスレッドの数です。ループはセマフォで待機し、セマフォを取得するとタスクをキューに入れます。
Semaphore ThreadsAvailable = new Semaphore(10, 10);
while (Queue.Count > 0)
{
ThreadsAvailable.WaitOne();
// Must dequeue item here, otherwise you could run off the end of the queue
ThreadPool.QueueUserWorkItem(DoStuff, Queue.Dequeue());
}
// Wait for remaining threads to finish
int threadCount = 10;
while (threadCount != 0)
{
ThreadsAvailable.WaitOne();
--threadCount;
}
void DoStuff(object item)
{
ItemType theItem = (ItemType)item;
// process the item
StartProcessing(item);
// And then release the semaphore so another thread can run
ThreadsAvailable.Release();
}
アイテムはメイン ループでキューから取り出されます。これは、処理が面倒な競合状態を回避するためです。スレッドにアイテムをデキューさせる場合、スレッドはこれを行う必要があります。
lock (queue)
{
if (queue.Count > 0)
item = queue.Dequeue();
else
// There wasn't an item to dequeue
return;
}
そうしないと、キューにアイテムが 1 つしか残っていないときに、次の一連のイベントが発生する可能性があります。
main loop checks Queue.Count, which returns 1
main loop calls QueueUserWorkItem
main loop checks Queue.Count again, which returns 1 because the thread hasn't started yet
new thread starts and dequeues an item
main loop tries to dequeue an item and throws an exception because queue.Count == 0
そのように物事を処理する気があるなら、あなたは大丈夫です。Release
重要なのは、スレッドが終了する前にスレッドがセマフォで呼び出すことを確認することです。明示的に管理されたスレッド、またはThreadPool
私が投稿したアプローチでそれを行うことができます。ThreadPool
スレッドを明示的に管理するよりも簡単だと思ったので、使用しました。