c# - 多个生产者单个消费者锁定模式

标签 c# multithreading

我有多个生产线程和单个消费线程。在 C# 中,我使用 ConcurrentQueue 来实现此目的。

当队列为空时,如何正确让消费者线程进入休眠状态?

ManualResetEventSlim signal;
void WorkerThread(CancellationToken token)
{
    while(!token.IsCancellationRequested)
    {
        object work;
        if (!_eventQueue.TryDequeue(out work))
        {
            signal.Reset();
            signal.Wait(token);
            continue;
        }
        ...
    }
}
...
void Produce(object o)
{
    _eventQueue.Enqueue(o);
    signal.Set();
}

我尝试过这个,但有一些机会,

  1. 线程 B 无法从 _eventQueue 读取数据
  2. 线程 A 写入 _eventQueue
  3. 线程A设置信号
  4. 线程 B 重置信号
  5. 线程 B 无限期等待

如何克服这个问题?以前,我使用了 lock()Monitor.Wait()AutoResetEvent 可能会有所帮助(它会在成功 Wait 时重置),但它不支持 CancellationToken

最佳答案

您可以使用BlockingCollection类来支持多个生产者和单个消费者的情况。

创建 BlockingCollection 类型的对象像这样:

BlockingCollection<object> collection = new BlockingCollection<object>(); //You can have a specific type instead of object if you want

生产者可以简单地调用Add将项目添加到集合的方法如下:

collection.Add("value");

消费者可以使用GetConsumingEnumerable获取 IEnumerable<T> 的方法从集合中获取项目。当没有更多项目时,此类枚举将阻塞(等待更多项目)。这个方法也supports cancellation .

foreach (var item in collection.GetConsumingEnumerable())
{
    //Consume item
}

如果您调用 CompleteAdding 方法,那么一旦没有更多的项目,消耗的枚举就会完成。

此类是完全线程安全的。

关于c# - 多个生产者单个消费者锁定模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34255759/

相关文章:

c# - Entity Framework 和延迟加载的问题

c# - 使用 UI 自动化以编程方式打开上下文菜单?

c++ - POSIX - pthread_kill()?

java - 当线程被销毁时,变量会被销毁吗?

multithreading - 从 OnTimer 事件访问父窗体中的变量 - 获取异常

c++ - 多线程建议

c# - Web 浏览器组件是 IE7 不是 IE8?如何改变这个?

c# 包含字符串的一部分

c# - 如何从 double 转换为 Int64

python-3.x - 使用tornado.ioloop.IOLoop.run_in_executor时如何避免线程过多?