.net - .NET中的生产者消费者链和线程调度

标签 .net multithreading synchronization

我制作了由4个生产者-消费者线程组成的链(形成4个步骤的管道)。令我惊讶的是,所有四个线程都按顺序运行,而不是同时运行!!!也就是说,第二个线程神秘地等待直到第一个线程完全完成生成为止。第三个线程神秘地等待直到第二个线程完全完成生成(依此类推)。

情况变得更糟。如果我将Thread.Sleep(300)放入第一个生产者的循环中,则其他三个线程将并发并实际上获得处理器时间,如预期的那样,并从多线程应用程序产生预期的“随机交错”控制台输出。我几乎无法接受“ sleep ”是解决方案的必要部分的想法,但是我看到code written by Jon Skeet正是以这种方式合并了 sleep 。

请告诉我,实现并发不是必需的,如果是并发,那么为什么是

关于我的特定生产者-消费者链的一个更精确的故事看起来像这样:

  • 第一个线程:处于紧密循环中,它会尽快生成“窗口小部件”消息,并将其插入下一个线程的队列中。当第一个窗口小部件添加到队列时,System.Threading.Timer设置为〜100毫秒。从计时器触发的回调是第二个线程...
  • 第二个线程(从计时器触发):从先前的队列中读取部分或全部小部件。它将它们发送到另一个队列(由第三个线程使用)。 monitor.Pulse/Wait机制用于与第三个线程同步。
  • 第三线程:在监视器上阻塞。等待直到monitor.Pulse被调用,然后从队列中获取一项。将一项插入最终队列,再次使用Monitor.Push完成后将其插入。
  • 第四个线程:在监视器上阻塞。请等待直到monitor.Pulse被调用。小部件已处理。

  • 要通过此管道处理100万个小部件,大约需要4分钟。在4分钟内,有足够的时间安排最后3个线程,并与第一个线程同时进行一些工作。但是正如我说的那样,最后三个线程是按顺序运行的,除非我为第一个线程引入了微小的 sleep 。这没有道理。

    对为什么这样工作有任何想法吗?

    p.s.请不要告诉我,正如我所描述的,长长的生产者-消费者链可以被缩减或消除。请相信我(或假设)我需要那么长的链条。 :)

    最佳答案

    紧密循环会影响多线程。听起来您的第一个线程运行得足够快,以至于第二个线程甚至没有机会启动。 请注意,如果发生这种情况,那么顺序解决方案是最有效的。 :)

    由于您的生产者/消费者布局有些复杂,因此我假设您在实际数据中看不到此行为。

    尽管可以通过添加带有非零参数的Thread.Sleep(请参阅Joe Duffy's blog entry on why this works)来解决此问题,或者只是忽略它,但是更好的解决方案是限制第一个生产者/消费者队列的大小。这将只允许第一个线程产生一定数量的小部件,然后阻塞直到管道的其余部分有机会启动。

    .NET 4.0 BlockingCollection<T>允许您指定最大大小。 Microsoft Rx library已将其反向移植到.NET 3.5,因此您可以根据需要使用它。 (我建议这样做,而不要使用内部解决方案)。

    关于.net - .NET中的生产者消费者链和线程调度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3535276/

    相关文章:

    .net - 加速跨AppDomain通信

    c++ - 在 C++ 中创建标准线程会使程序崩溃

    java - 查找 JVM 崩溃的原因

    java - android 在 GridView 更新之间等待

    javascript - 使用 Ajax 时检查客户端和服务器的同步状态

    c# - ASP.NET 在另一个客户端上更新 UpdatePanel

    .net - 我应该担心混淆我的 .NET 代码吗?

    c - 同步两个线程

    c# - 如何在订阅开始之前延迟从 IObservable 获取元素?

    java - 计数器的线程安全与非线程安全实现