这很容易用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;
}
否则,当队列中只剩下一个项目时,可能会发生以下事件序列。
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
它,因为我发现它比显式管理线程更容易。