2012-03-24 105 views
0

我已经使用BlockingCollection实现了生产者/消费者模式,但它并没有像我期望的那样被阻塞。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,告诉我我拉的框架正在其他地方使用。

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

它并不总是马上发生,但我已经注意到了这一点,只有当队列为空或接近空(即消费者比生产者更快),所以我猜这是发生与添加的第一张图片或拍摄的最后一张图片有关。任何想法,为什么这可能会发生?

+1

好吧,看来你*是*在两个地方使用图像。一个是收集的消费者,另一个是事件处理程序。这很可能是你的问题。 'BlockingCollection'不知道你可能做的其他事情,它不会帮助你做到这一点。 – svick 2012-03-24 03:42:10

回答

0

执行video_NewFrame的线程在传递到NewFrame事件处理函数时正在使用图像。由于这与Run同时运行,所以没有什么能够阻止两个线程同时访问image。 (当Run离队的图像,而NewFrame事件处理程序处理呢?这只会发生,这也解释了为什么你看到它,只有当队列为空或近空。)

一个补丁修复可能是将呼叫转移到NewFramequeue.Add(image);video_NewFrame)。这将确保Run在事件处理程序完成后才能看到它(假设事件处理程序不存储对其的引用)。

+0

你和svick是对的,问题是事件处理程序。我原以为NewFrameEventArgs会引发一个副本,而不是引用其订阅者。无论我是添加到队列还是先打开NewFrame,解决方案都是确保我使用的是克隆,因此第二个操作不使用相同的引用。谢谢! – hspim 2012-03-24 04:06:05