首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C#生产者-使用Monitor.Wait和Monitor.Pulse的消费者模式

C#生产者-使用Monitor.Wait和Monitor.Pulse的消费者模式
EN

Stack Overflow用户
提问于 2014-01-30 19:28:06
回答 1查看 1.5K关注 0票数 1

考虑以下阻塞生产者和使用者线程的实现:

代码语言:javascript
复制
static void Main(string[] args)
{
  var syncRoot = new object();
  var products = new List<int>();

  Action producer = () => {
    lock (syncRoot)
    {
      var counter = 0;
      while (true)
      {
        products.Add(counter++);
        Monitor.Pulse(syncRoot);
        Monitor.Wait(syncRoot);
      }
    }};

  Action consumer = () => {
    lock (syncRoot)
      while (true)
      {
        Monitor.Pulse(syncRoot);
        products.ForEach(Console.WriteLine);
        products.Clear();
        Thread.Sleep(500);

        Monitor.Wait(syncRoot);
      }};

  Task.Factory.StartNew(producer);
  Task.Factory.StartNew(consumer);

  Console.ReadLine();
}

假设当生成线程进入Monitor.Wait时,它等待两件事情:

  1. 从消费者线上发出的脉冲,以及
  2. 用于重新获取锁

在上面的代码中,我在PulseWait调用之间做了大量的工作。

因此,如果我这样写我的消费线程(在等待之前立即执行):

代码语言:javascript
复制
  Action consumer = () =>
  {
    lock (syncRoot)
      while (true)
      {
        products.ForEach(Console.WriteLine);

        products.Clear();
        Thread.Sleep(500);

        Monitor.Pulse(syncRoot);
        Monitor.Wait(syncRoot);
      }
  };

我没注意到行为上有任何变化。这方面有什么指引吗?我们是否应该在紧接Pulse之前使用Wait,还是在性能方面存在差异?

EN

回答 1

Stack Overflow用户

发布于 2014-01-30 20:18:06

  • 脉冲然后等待几乎是相同的等待然后脉冲,因为它们是在一个无限循环中运行。脉冲,等待几乎等同于等待,脉冲,等待,脉冲
  • 通常,等待更改的线程使用Wait,执行更改的线程使用Pulse。线程可以两者兼顾,但一般实践取决于具体情况。
  • 给出的代码是在保持锁的同时睡觉。为了学习/模拟的目的,这是很好的,但生产代码一般不应该这样做。您可以将超时传递给Wait,这很好,并且在等待期间不持有锁。
  • 一般来说,Monitor被认为是一个低级同步原语,建议使用更高级别的同步原语。理解Monitor这样的低级原语是很好的,但一般的智慧是,对于几乎任何实际场景,都有一些更高级别的原语,它们不太容易出错,不太可能隐藏一些棘手的竞赛场景,而且更容易在其他人的代码中阅读。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21465733

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档