我有这个生产者/消费者代码:
主要:
static void Main()
{
using(PCQueue q = new PCQueue(2))
{
for(int i = 0; i < 10; i++)
{
int itemNumber = i; // To avoid the captured variable trap
q.EnqueueItem(() = > {
Thread.Sleep(1000); // Simulate time-consuming work
Console.Write(" Task" + itemNumber);
});
}
Console.WriteLine("Enqueued 10 items");
Console.WriteLine("Waiting for items to complete...");
}
}
CLASS:
public class PCQueue: IDisposable
{
readonly object _locker = new object();
Thread[] _workers;
Queue < Action > _itemQ = new Queue < Action > ();
public PCQueue(int workerCount)
{
_workers = new Thread[workerCount];
// Create and start a separate thread for each worker
for(int i = 0; i < workerCount; i++)
(_workers[i] = new Thread(Consume)).Start();
}
public void Dispose()
{
// Enqueue one null item per worker to make each exit.
foreach(Thread worker in _workers) EnqueueItem(null);
}
public void EnqueueItem(Action item)
{
lock(_locker)
{
_itemQ.Enqueue(item); // We must pulse because we're
Monitor.Pulse(_locker); // changing a blocking condition.
}
}
void Consume()
{
while(true) // Keep consuming until
{ // told otherwise.
Action item;
lock(_locker)
{
while(_itemQ.Count == 0) Monitor.Wait(_locker);
item = _itemQ.Dequeue();
}
if(item == null) return; // This signals our exit.
item(); // Execute item.
}
}
}
问题:
让我们说执行item();
需要很长时间。
1) we enqueue a new work and pulse. ( 1 consumer is busy now)
2) we enqueue a new work and pulse. ( second consumer is busy now)
3) we enqueue a new work and pulse.
现在?两个线程都很忙!
我know 脉搏会丢失(或不会?)
唯一的解决方案是将其更改为AutoResetEvent
吗?
答案 0 :(得分:3)
现在?两个线程都很忙! 我知道脉冲会丢失(或不会?)
是的,当(所有)线程忙于执行Item()调用时,Pulse将丢失。
但这不一定是个问题,你在每个Enqueue()之后都是Pulsing,并且只有当queue.Count从0变为1时才需要Pulse。你需要更多的脉冲。
但是当你试图优化脉冲数时,你可能会遇到麻烦。 Wait / Pulse无状态的事实意味着你应该小心使用它。