【发布时间】:2011-04-01 21:45:15
【问题描述】:
我创建了一个由 4 个生产者-消费者线程组成的链(形成一个 4 步管道)。令我惊讶的是,所有四个线程都按顺序运行,而不是同时运行!!!也就是说,第二个线程神秘地等待,直到第一个线程完全完成生产。第三个线程神秘地等待,直到第二个线程完全完成生产(依此类推)。
情况变得更糟。如果我将 Thread.Sleep(300) 放入第一个生产者的循环中,那么其他三个线程将变为并发并实际获得处理器时间,正如预期的那样,从多线程应用程序中产生“随机交错”控制台输出。我几乎无法接受“睡眠”是解决方案的必要部分的想法,但我看到在code written by Jon Skeet 中以这种方式完全结合了睡眠。
请告诉我实现并发不是必需的,或者如果是,那么为什么?
关于我的特定生产者-消费者链的更准确的故事如下所示:
- 第一个线程:在一个紧密的循环中,它尽可能快地生成“小部件”消息,并将它们推入队列以供下一个线程使用。当第一个小部件添加到队列中时,System.Threading.Timer 设置为 ~100 毫秒。计时器触发的回调是第二个线程...
- 第二个线程(从计时器触发):从前一个队列中读取部分或全部小部件。它将它们发送到另一个队列(由第三个线程使用)。 monitor.Pulse/Wait 机制用于与第三个线程同步。
- 第三线程: 在监视器上阻塞。等到 monitor.Pulse 被调用,然后从队列中获取一项。一项被推送到最终队列中,推送完成后再次使用 monitor.Pulse。
- 第四个线程: 在监视器上阻塞。等到 monitor.Pulse 被调用。小部件已处理。
通过此管道处理 100 万个小部件大约需要 4 分钟。在 4 分钟内,有足够的时间安排最后 3 个线程并与第一个线程同时执行一些工作。但正如我所说,最后三个线程按顺序运行,除非我为第一个线程引入一个小睡眠。没有意义。
对为什么会这样工作有什么想法吗?
附言请不要告诉我,正如我所描述的那样,一条长的生产者-消费者链可以缩小或消除。请相信我(或假设)我需要这么长的链条。 :)
【问题讨论】:
-
看起来您遇到了锁定问题。如果没有详细的代码示例,不要指望任何更有用的答案。
-
最好使用提供的系统机制;特别是,
BlockingCollection<T>用于队列,Task用于任务。 -
@Stephen:我使用的是 .net 3.5,它没有 BlockingCollection。
-
基于 Thread.Sleep() 的 XML 文档,显然这种“线程按顺序运行问题”是正常行为。 sleep 的文档说使用 '0' 毫秒“表示应该暂停该线程以允许其他等待线程执行。”奇怪的是,Thread.Sleep(1) 完全解决了这个问题,而 Thread.Sleep(0) 什么也没做。尽管如此,如果某些事情需要它(即我的问题),文档不会提供这意味着。不过,我认为现在这整个事情都是正常的行为——尽管它仍然让我觉得很疯狂。
-
@Mystagogue:Rx library 包括 .NET 3.5 的
BlockingCollection<T>和Task,如果您有兴趣的话。
标签: .net multithreading synchronization