2012-08-14 84 views
2

我有一個Windows窗體用戶控件,它包含第三方圖像顯示控件,它使用BeginInvoke委託調用從單獨的線程更新。在CPU負載過重的情況下發生跨線程BeginInvoke阻塞

在CPU負載過重的情況下,UI鎖定。當我附加一個調試器時,它總是在它更新第三方圖像控件的同一行代碼中。

public ICogImage DisplayImage 
    { 
     get { return this.ResultImageCogDisplay.Image; } 
     set 
     { 
      this.BeginInvoke((ThreadStart)delegate 
      { 
       this.ResultImageCogDisplay.Image = value; 
      }); 

     } 
    } 

如果我註釋掉setter的實現,那麼問題就會消失。

任何人都可以解釋爲什麼會發生這種情況嗎?

一些更多的信息:

  • 更新事件週期性地生成的圖像(〜200毫秒)從一個幀捕獲卡。事件在單獨的線程中引發。
  • 我相信第三方圖像控件使用ActiveX,它是康耐視視覺處理框架的一部分。
  • 圖像是大約。 900x800 8位灰度
  • 窗體上有4個這些控件,每個控件從不同的圖像的不同線程餵食。
  • 我試過了,沒有IsInvokeRequired()檢查,它似乎沒有任何區別。

PostMessage隊列上的消息數量是否有限制?我在高CPU負載下遇到了什麼限制?

回答

4

BeginInvoke排隊要在UI線程上執行的操作。如果你排隊足夠的事情來做到UI無法跟上他們,你會壓倒UI線程,它會出現掛起。嘗試將事件重新限制回可能每秒一次,以查看是否有幫助。

+0

是否有可能找到這個隊列上的消息數量,只是爲了證明其原因?圖像數據量我會在隊列中張貼是一個因素(我可以縮小圖像)。不幸的是,應用程序必須顯示圖像作爲其用於手工製作的QA製作過程。 – canice 2012-08-14 23:10:11

+0

數據量,數據處理速度等等。是UI線程能否跟上的一個因素。我不認爲有一種方法可以證明它,但是如果數據和數據緩解了問題,那麼限制數量會告訴你很多。 – 2012-08-15 00:27:14

+1

嘗試在發佈代碼時將'Console.WriteLine'發佈到捕獲DateTime.Now'的UI線程,並從代碼實際執行的'DateTime.Now'中減去它。然後,您可以確定UI線程正在經歷的近似延遲。如果你需要它更準確,那就試試用'StopWatch'。 – Enigmativity 2012-08-15 02:56:29

0

Windows消息隊列條目(至少在32位系統上)的確有10,000個條目的限制。早在這種情況發生之前,通過發佈消息比GUI更容易處理它們 - 我經常這樣做:((

通常,我的設計使用一個對象池用於線程間comms,所以我解決了這個問題,因爲生產者線程在池隊列中被阻塞,如果GUI沒有足夠快地返回'used'對象,那麼提供整體流量控制。當然,在停止GUI鎖定時,這並沒有幫助很多,如果你有一個幀率不能滿足要求:(

+0

我從BeginInvoke更改爲Invoke,雖然它會阻止調用方法,直到更新完成(同步) - 但它沒有任何不同。說,上面的DisplayImage屬性從事件處理程序更新了大約3-4個級別,其中一些使用了Delegate.BeginInvoke(),其中(AFAIK)使用與您使用的線程池相似的線程池 - 但是您將擁有更多的控制權超過游泳池的大小。 – canice 2012-08-15 00:03:40

+0

我使用framegrabber進行數字I/O握手,可以跳過/拒絕正在檢查的下一個產品,因此如果我可以減慢圖像更新速度以達到可接受的速度(這不會掛起UI),那麼我可能會有一個解決方案。謝謝您的幫助。 – canice 2012-08-15 00:10:58

+1

從BeginInvoke更改爲Invoke可能不會減少工作量;但可能確實意味着隊列未被超載。調用只是阻止當前線程並讓UI調用該操作。如果您仍然有懸掛問題,設置DisplayImage並顯示圖像的工作量可能無法以每秒4-5次的速度完成。並不是很多正常的控件能夠獲得大部分的「幀頻」,他們預計會顯示一次靜止圖像。 – 2012-08-15 02:23:56