【问题标题】:BlockingCollection, race condition?BlockingCollection,竞争条件?
【发布时间】:2012-03-24 02:35:28
【问题描述】:

我已经使用 BlockingCollection 实现了生产者/消费者模式,但它似乎并没有像我预期的那样阻塞。

我有一个线程从网络摄像头接收帧并将它们添加到 BlockingCollection

private void video_NewFrame(object sender, NewFrameEventArgs eventArgs) {
    image = (Bitmap)eventArgs.Frame.Clone();
    queue.Add(image);
    if (NewFrame != null)
        NewFrame(this, new NewFrameEventArgs(image)); //invoke the event for display
}

在另一个线程中,我引用了集合并使用处理框架

public void Run() {
    foreach (Bitmap bmp in queue.GetConsumingEnumerable()) {
        // process bitmap

但是,正如您在下面看到的,它往往会引发 InvalidOperationException,告诉我我正在拉的 Frame 正在其他地方使用。

img http://i17.photobucket.com/albums/b52/orubap/2012-03-24_020858.png

它并不总是立即发生,但我注意到它仅在队列为空或接近空时发生(即消费者比生产者快)所以我猜这与第一个有关添加的图像或拍摄的最后一张图像。任何想法为什么会发生这种情况?

【问题讨论】:

  • 好吧,看来您正在在两个地方使用该图像。一个在集合的消费者中,另一个是事件处理程序。这很可能是你的问题。 BlockingCollection 不知道您可能正在做的其他事情,这对您没有帮助。

标签: c# multithreading blockingcollection


【解决方案1】:

执行video_NewFrame 的线程在将图像传递给NewFrame 事件处理程序时正在使用该图像。由于它与Run 同时运行,因此没有什么可以阻止两个线程同时访问image。 (这只会在Run 将图像出列而NewFrame 事件处理程序正在处理它时发生,这解释了为什么只有在队列为空或几乎为空时才能看到它。)

一种解决方法可能是将呼叫转移到NewFrame 之前 queue.Add(image);(在video_NewFrame)。这将确保Run 在事件处理程序完成之前无法看到它(假设事件处理程序不存储对它的引用)。

【讨论】:

  • 你和 svick 是对的,问题是事件处理程序。我曾认为 NewFrameEventArgs 会触发副本而不是对其订阅者的引用。无论我是添加到队列中还是先启动 NewFrame,解决方案都是确保我使用的是克隆,因此第二个操作没有使用相同的引用。谢谢!
猜你喜欢
  • 1970-01-01
  • 2022-01-23
  • 2018-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多