Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 生产者-消费者队列未处理_C#_.net_.net 4.0_Queue_Producer Consumer - Fatal编程技术网

C# 生产者-消费者队列未处理

C# 生产者-消费者队列未处理,c#,.net,.net-4.0,queue,producer-consumer,C#,.net,.net 4.0,Queue,Producer Consumer,我已经构建了一个生产者-消费者队列,它包装了.net 4.0的ConcurrentQueue,并在基于线程的生产(排队)和消费(while(true))之间使用事件信令。 队列看起来像: public class ProducerConsumerQueue<T> : IDisposable, IProducerConsumerQueue<T> { private bool _IsActive=true; public int Count {

我已经构建了一个生产者-消费者队列,它包装了.net 4.0的ConcurrentQueue,并在基于线程的生产(排队)和消费(while(true))之间使用事件信令。 队列看起来像:

public class ProducerConsumerQueue<T> : IDisposable, IProducerConsumerQueue<T>
{
    private bool _IsActive=true;

    public int Count
    {
        get
        {
            return this._workerQueue.Count;
        }
    }

    public bool IsActive
    {
        get { return _IsActive; }
        set { _IsActive = value; }
    }

    public event Dequeued<T> OnDequeued = delegate { };
    public event LoggedHandler OnLogged = delegate { };

    private ConcurrentQueue<T> _workerQueue = new ConcurrentQueue<T>();

    private object _locker = new object();

    Thread[] _workers;

    #region IDisposable Members

    int _workerCount=0;

    ManualResetEventSlim _mres = new ManualResetEventSlim();

    public void Dispose()
    {
        _IsActive = false;

        _mres.Set();

        LogWriter.Write("55555555555");

          for (int i = 0; i < _workerCount; i++)
          // Wait for the consumer's thread to finish.
          {
             _workers[i].Join();        
          }
           LogWriter.Write("6666666666");
     // Release any OS resources.
    }
    public ProducerConsumerQueue(int workerCount)
    {
        try
        {
            _workerCount = 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(Work)).Start();
        }
        catch (Exception ex)
        {
            OnLogged(ex.Message + ex.StackTrace);
        }

    }
    #endregion

    #region IProducerConsumerQueue<T> Members

    public void EnqueueTask(T task)
    {
        if (_IsActive)
        {
            _workerQueue.Enqueue(task);
            //Monitor.Pulse(_locker);
            _mres.Set();
        }
    }

    public void Work()
    {
      while (_IsActive)
      {
          try
          {
              T item = Dequeue();
              if (item != null)
                  OnDequeued(item);
          }
          catch (Exception ex)
          {
              OnLogged(ex.Message + ex.StackTrace);
          }              
      }
    }

    #endregion
    private T Dequeue()
    {
        try
        {
            T dequeueItem;
            //if (_workerQueue.Count > 0)
            //{
            _workerQueue.TryDequeue(out dequeueItem);
            if (dequeueItem != null)
                return dequeueItem;
            //}
            if (_IsActive)
            {
                _mres.Wait();
                _mres.Reset();
            }
            //_workerQueue.TryDequeue(out dequeueItem);
            return dequeueItem;
        }
        catch (Exception ex)
        {
            OnLogged(ex.Message + ex.StackTrace);
            T dequeueItem;
            //if (_workerQueue.Count > 0)
            //{
            _workerQueue.TryDequeue(out dequeueItem);
            return dequeueItem;
        }

    }


    public void Clear()
    {
        _workerQueue = new ConcurrentQueue<T>();
    }
}
公共类ProducerConsumerQueue:IDisposable,IProducerConsumerQueue
{
private bool _IsActive=true;
公共整数计数
{
得到
{
返回此。\u workerQueue.Count;
}
}
公共福利活动
{
获取{return\u IsActive;}
设置{u IsActive=value;}
}
public event Dequeued OnDequeued=委托{};
public event LoggedHandler OnLogged=委托{};
私有ConcurrentQueue_workerQueue=新ConcurrentQueue();
私有对象_locker=新对象();
线程【】u工人;
#区域IDisposable成员
int_workerCount=0;
ManualResetEventSlim\u mres=新的ManualResetEventSlim();
公共空间处置()
{
_IsActive=假;
_mres.Set();
LogWriter.Write(“55555”);
对于(int i=0;i<\u workerCount;i++)
//等待消费者的线程完成。
{
_工人[i].Join();
}
日志编写器。写入(“6666”);
//释放任何操作系统资源。
}
public ProducerConsumerQueue(int workerCount)
{
尝试
{
_workerCount=workerCount;
_工人=新线程[工人计数];
//为每个工作线程创建并启动一个单独的线程
对于(int i=0;i0)
//{
_workerQueue.TryDequeue(out-dequeueItem);
if(出列项!=null)
返回出列项;
//}
如果(_IsActive)
{
_mres.Wait();
_mres.Reset();
}
//_workerQueue.TryDequeue(out-dequeueItem);
返回出列项;
}
捕获(例外情况除外)
{
onloged(例如Message+ex.StackTrace);
T排队项;
//如果(_workerQueue.Count>0)
//{
_workerQueue.TryDequeue(out-dequeueItem);
返回出列项;
}
}
公共空间清除()
{
_workerQueue=新的ConcurrentQueue();
}
}
}

调用Dispose时,它有时会阻塞连接(一个线程消耗),Dispose方法会被卡住。我猜它会在resetEvents等待时被卡住,但为此,我调用了Dispose上的set。
有什么建议吗?

更新:我理解您关于内部需要队列的观点。我建议使用
BlockingCollection
是基于这样一个事实,即您的代码包含大量逻辑来提供阻塞行为。自己编写这样的逻辑很容易出现错误(我从经验中知道这一点);因此,当框架中有一个现有类为您至少做了一些工作时,通常最好使用该类

关于如何使用
BlockingCollection
实现这个类的完整示例太大了一点,无法包含在这个答案中,因此我发布了一个工作示例;请随意看看您的想法

我还编写了一个示例程序来演示上述示例

我的代码正确吗?我不会太自信地说“是”;毕竟,我没有编写单元测试,也没有对其运行任何诊断等。这只是一个基本草案,让您了解如何使用
BlockingCollection
而不是
ConcurrentQueue
清理大量逻辑(在我看来)并且更容易将注意力集中在类的主要目的(从队列中消费项目并通知订阅者)上,而不是其实现的困难方面(内部队列的阻塞行为)


评论中提出的问题:

您不使用
阻止集合
的任何原因

你的回答是:

[…]我需要排队

从:

默认的基础集合是

如果您选择实现自己的类而不是使用
BlockingCollection
的唯一原因是您需要一个FIFO队列,那么……您可能需要重新考虑您的决定。使用默认无参数构造函数实例化的
BlockingCollection
是一个FIFO队列

也就是说,虽然我不认为我可以对您发布的代码进行全面的分析,但我至少可以提供一些建议:

  • 我会非常犹豫是否要像您在这里为一个处理如此棘手的多线程行为的类使用事件。调用代码可以附加它想要的任何事件处理程序,而这些事件处理程序又会抛出异常(您无法捕获),阻塞很长一段时间,甚至可能由于完全超出您控制范围的原因而导致死锁,这在阻塞队列的情况下是非常糟糕的
  • 您的
    Dequeue
    Dispose
    m中存在竞争条件
    if (_IsActive) // point A
    {
        _mres.Wait(); // point C
        _mres.Reset(); // point D
    }
    
    _IsActive = false;
    
    _mres.Set(); // point B
    
    private volatile bool _IsActive=true;