【发布时间】:2012-08-02 22:03:03
【问题描述】:
我有这个生产者/消费者代码:
主要:
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...");
}
}
类:
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吗?
【问题讨论】:
-
System.Collections.Concurrent.BlockingCollection 有什么问题?如果你想DIY,你可以使用System.Threading.Semaphore 和一个锁。事件不是生产者-消费者队列的合适解决方案 - 我不知道为什么这么多开发人员被欺骗使用它们来实现这样的目的。
-
@MartinJames 没有错。我只想知道如何增强代码,并检查我的假设是否正确。
-
@MartinJames 我想您将不得不向 Joe Albahari 询问您的问题。books.google.co.il/…
-
使用信号量 - 它可以与多个生产者/消费者一起正常工作。 AutoResetEvent 可能与多个生产者/消费者一起正常工作,也可能无法正常工作。我从来没有费心去测试它,因为它只是不适合使用的同步器。
-
你真的发现问题了吗?
标签: c# .net multithreading monitor