[英]Why does my producer blocks forever sometimes?
我正在嘗試使用Monitor
在C#
實現生產者/消費者類。 想法是消費者必須阻止,直到生產者有一些消費者的項目,但生產者應繼續生產。 我的制作人制作了一些項目,然后等待/休息一段時間再制作。
問題我看到制作人永遠不會從Thread.Sleep(time)
醒來。 也許在某個地方存在僵局。
請幫我理解這個。
就像一個注釋,我不想使用BlockingCollection
......這是我的代碼......
public class ProducerConsumerEx
{
private object _objLocker = new object();
private Thread _tProducer;
private Queue<string> _producerQueue;
private bool _keepProducing;
public ProducerConsumerEx()
{
_keepProducing = false;
_producerQueue = new Queue<string>();
_tProducer = new Thread(Produce);
_tProducer.IsBackground = true;
}
private void Produce()
{
while (_keepProducing)
{
Console.WriteLine($"PRODUCER {Thread.CurrentThread.ManagedThreadId} LOOP");
lock (_objLocker)
{
string item = DateTime.Now.ToString("HH:mm:ss");
_producerQueue.Enqueue(item);
Console.WriteLine($"PRODUCER {DateTime.Now.ToString("HH:mm:ss")} Thread {Thread.CurrentThread.ManagedThreadId} Inserted {item}");
Monitor.Pulse(_objLocker);
Console.WriteLine($"PRODUCER {DateTime.Now.ToString("HH:mm:ss")} Thread {Thread.CurrentThread.ManagedThreadId} AF Pulse {item}");
}
Console.WriteLine($"PRODUCER {DateTime.Now.ToString("HH:mm:ss")} Thread {Thread.CurrentThread.ManagedThreadId} BF Sleep");
Thread.Sleep(10000);
Console.WriteLine($"PRODUCER {DateTime.Now.ToString("HH:mm:ss")} Thread {Thread.CurrentThread.ManagedThreadId} AF Sleep");
}
}
public void Start()
{
if (!_keepProducing)
{
_tProducer.Start();
_keepProducing = true;
}
}
public string Consume()
{
string val = default(string);
Console.WriteLine($"CONSUMER {DateTime.Now.ToString("HH:mm:ss")} Thread {Thread.CurrentThread.ManagedThreadId} BF Consume");
lock (_objLocker)
{
Console.WriteLine($"CONSUMER {DateTime.Now.ToString("HH:mm:ss")} Thread {Thread.CurrentThread.ManagedThreadId} BF Consume Inside");
if (_producerQueue.Count > 0)
{
val = _producerQueue.Dequeue();
}
else
{
Console.WriteLine($"CONSUMER {DateTime.Now.ToString("HH:mm:ss")} Thread {Thread.CurrentThread.ManagedThreadId} WAITING");
Monitor.Wait(_objLocker);
//
if (_producerQueue.Count > 0)
{
val = _producerQueue.Dequeue();
}
}
}
return val;
}
}
這個類的使用是這樣的
static void Main(string[] args)
{
ProducerConsumerEx pc = new ProducerConsumerEx();
pc.Start();
while (true)
{
string t = pc.Consume();
Console.WriteLine($"Main {t}");
}
}
為了實現消費者/生產者模式,我建議使用BlockingCollection
:
一個小例子:
private BlockingCollection<string> _producerQueue;
void Consume()
{
foreach (var item in _producerQueue.GetConsumingEnumerable())
{
//do some work there
}
}
void Produce()
{
_producerQueue.Add("a string to consume");
}
public void Start()
{
Task.Factory.StartNew(Consume);
}
來自MSDN:
https://msdn.microsoft.com/en-us/library/dd267312(v=vs.110).aspx
為實現IProducerConsumerCollection的線程安全集合提供阻塞和綁定功能。
你可以在那里找到一些例子:
你Monitor.Wait(_objLocker);
在lock (_objLocker)
語句中。 這樣生產者永遠不會添加和發信號通知消費者。 你應該帶上Monitor.Wait(_objLocker);
lock (_objLocker)
外lock (_objLocker)
像:( 偽)
public string Consume()
{
string val = default(string);
Console.WriteLine($"CONSUMER {DateTime.Now.ToString("HH:mm:ss")} Thread {Thread.CurrentThread.ManagedThreadId} BF Consume");
int count = 0;
lock (_objLocker)
count = _producerQueue.Count;
if (count == 0)
{
Console.WriteLine($"CONSUMER {DateTime.Now.ToString("HH:mm:ss")} Thread {Thread.CurrentThread.ManagedThreadId} WAITING");
Monitor.Wait(_objLocker);
}
lock (_objLocker)
val = _producerQueue.Dequeue();
return val;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.