繁体   English   中英

C#中的producer-consumer队列中的ArgumentException

[英]ArgumentException in producer-consumer queue in C#

在此输入图像描述 我有一个生产者/消费者队列如下,但我得到ArgumentWException

以下是代码:

public class ProducerConsumer<T> where T : class
    {
        #region Private Variables
        private Thread _workerThread;
        private readonly Queue<T> _workQueue;
        private  object _enqueueItemLocker = new object();
        private  object _processRecordLocker = new object();
        private readonly Action<T> _workCallbackAction;
        private AutoResetEvent _workerWaitSignal;
        #endregion

        #region Constructor
        public ProducerConsumer(Action<T> action)
        {
            _workQueue = new Queue<T>();
            _workCallbackAction = action;

        }
        #endregion
        #region Private Methods 
        private void ProcessRecord()
        {
            while (true)
            {               
                T workItemToBeProcessed = default(T);
                bool hasSomeWorkItem = false;
                lock (_processRecordLocker)
                {
                    hasSomeWorkItem = _workQueue.Count > 0;

                    if (hasSomeWorkItem)
                    {
                        workItemToBeProcessed = _workQueue.Dequeue();
                        if (workItemToBeProcessed == null)
                        {
                            return;
                        }
                    }
                }
                if (hasSomeWorkItem)
                {
                    if (_workCallbackAction != null)
                    {
                        _workCallbackAction(workItemToBeProcessed);
                    }
                }
                else
                {
                    _workerWaitSignal.WaitOne();
                }
            }
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Enqueues work item in the queue.
        /// </summary>
        /// <param name="workItem">The work item.</param>
        public void EnQueueWorkItem(T workItem)
        {
            lock (_enqueueItemLocker)
            {               
                _workQueue.Enqueue(workItem);

                if (_workerWaitSignal == null)
                {
                    _workerWaitSignal = new AutoResetEvent(false);
                }

                _workerWaitSignal.Set();
            }
        }
        /// <summary>
        /// Stops the processer, releases wait handles.
        /// </summary>
        /// <param name="stopSignal">The stop signal.</param>
        public void StopProcesser(AutoResetEvent stopSignal)
        {
            EnQueueWorkItem(null);

            _workerThread.Join();
            _workerWaitSignal.Close();
            _workerWaitSignal = null;

            if (stopSignal != null)
            {
                stopSignal.Set();
            }
        }
        /// <summary>
        /// Starts the processer, starts a new worker thread.
        /// </summary>
        public void StartProcesser()
        {
            if (_workerWaitSignal == null)
            {
                _workerWaitSignal = new AutoResetEvent(false);
            }
            _workerThread = new Thread(ProcessRecord) { IsBackground = true };
            _workerThread.Start();
        }
        #endregion
    }

另一课是:

public class Tester
{
    private readonly ProducerConsumer<byte[]> _proConsumer;
    public Tester()
    {
        _proConsumer = new ProducerConsumer<byte[]>(Display);
    }
    public void AddData(byte[] data)
    {
        try
        {
            _proConsumer.EnQueueWorkItem(recordData);
        }
        catch (NullReferenceException nre)
        {

        }
    }
    public void Start()
    {
        _proConsumer.StartProcesser();
    }

    private static object _recordLocker = new object();

    private void Display(byte[] recordByteStream)
    {
        try
        {
            lock (_recordLocker)
            {
                Console.WriteLine("Done with data:" + BitConverter.ToInt32(recordByteStream, 0));

            }

        }
        catch (Exception ex)
        {

        }

    }
}

而我的主要功能:

class Program
    {
        private static Tester _recorder;
        static void Main(string[] args)
        {
            _recorder = new Tester();
            _recorder.StartRecording();

            for (int i = 0; i < 100000; i++)
            {
                _recorder.AddRecordData(BitConverter.GetBytes(i));              
            }

            Console.Read();
        }
    }

知道为什么我会得到异常,我应该怎么做才能避免这种情况?

您的类在其当前实现中不是线程安全的。 您正在为Enqueuelock (_enqueueItemLocker) )和Dequeuelock (_processRecordLocker) )调用使用两个不同的对象,这会在Queue<T>创建竞争条件。

您需要在两个调用上锁定相同的对象实例 ,以便安全地使用队列。

如果您使用的是.NET 4,我建议使用ConcurrentQueue<T>BlockingCollection<T> ,因为它们可以消除代码中锁的需要,因为它们是线程安全的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM