簡體   English   中英

為什么我的制作人有時會永遠封鎖?

[英]Why does my producer blocks forever sometimes?

我正在嘗試使用MonitorC#實現生產者/消費者類。 想法是消費者必須阻止,直到生產者有一些消費者的項目,但生產者應繼續生產。 我的制作人制作了一些項目,然后等待/休息一段時間再制作。

問題我看到制作人永遠不會從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的線程安全集合提供阻塞和綁定功能。

你可以在那里找到一些例子:

http://dotnetpattern.com/csharp-blockingcollection

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM