繁体   English   中英

具有Monitor.Wait和Monitor.Pulse的C#生产者-消费者模式

[英]C# Producer-Consumer pattern with Monitor.Wait and Monitor.Pulse

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

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调用之间进行了繁琐的工作。

因此,如果我这样编写我的使用线程(在等待之前立即脉冲):

  Action consumer = () =>
  {
    lock (syncRoot)
      while (true)
      {
        products.ForEach(Console.WriteLine);

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

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

我没有发现任何行为上的变化。 有什么指导方针吗? 我们通常应该在Wait之前立即Pulse还是在性能方面有所不同?

  • “先脉冲再等待”与“先脉冲再等待”几乎相同,因为它们在无限循环中运行。 脉冲,等待,脉冲,等待与等待,脉冲,等待,脉冲几乎相同

  • 通常,等待更改的线程使用Wait ,而执行更改的线程使用Pulse 线程可以同时执行这两种操作,但是一般情况取决于情况。

  • 给定的代码在按住锁的同时正在休眠。 出于学习/模拟的目的,这很好,但是生产代码通常不应该这样做。 您可以将超时传递给Wait ,这很好,并且在等待期间不持有锁。

  • 一般来说,Monitor被视为低级同步原语,建议改用高级同步原语。 理解Monitor等低级原语是一件好事,但是通常的智慧是,对于几乎任何实际情况,都可以使用一些高级原语,这些原语不太容易出错,不太可能隐藏某些棘手的比赛情况,并且更容易在某人中阅读。其他的代码。

暂无
暂无

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

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