2012-03-24 108 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