2012-05-31 37 views
4

我的問題可能並不是真正的實時處理,但可能會再次。如何正確使用實時優先

我的應用程序有幾個比GUI更重要的線程,但是我希望GUI至少可以使用。我不希望它在任何時候都被鎖定,而且我確實希望更新屏幕給出我正在執行的處理結果。

目前我所有的基本項目都是在不同的線程中分離的,我調用一個委託給我的GUI來顯示結果。

我的GUI可以正常工作,但是如果我更改標籤頁或者最小化/最大化它,已經知道阻止我的其他線程在他們不能在0.1s的時間限制內執行操作。

這是我在做什麼打電話給我的委託:

delegate void FuncDelegate(ResultContainer Result); 
FuncDelegate DelegatedDisplay= new FuncDelegate(DisplayResults); 
//then later on 
Invoke(DelegatedDisplay, Result); 

我的大部分關鍵過程是在連續循環運行,從拉動和推動各種緩衝區(的ArrayList和正常列表)線程。

我的一個關鍵線程的啓動每次使用:

Thread mythread = new Thread(new ThreadStart(ProcessResults)); 
mythread.Start(); 

我想這樣做的原因,而不是隻具有在循環中運行一個線程,從名單拉,是我想也許我沒有時間的原因是我有一個輪詢循環,我擔心會佔用太多的資源(儘管每當輪詢結果爲負時我都使用Thread.Sleep(5))。

每次我需要併發進程花費我寶貴的時間,是否啓動新線程?這應該是一個循環?我的循環被責備?

我可以給一個線程比其他更高的優先級,還是使用Thread.Sleep我唯一的選擇?如果我確實分配了更高的線程優先級,我怎麼能確定其他線程能夠存活?

爲什麼簡單的表單事件會非常阻礙我的其他線程?有沒有辦法給我的GUI線程分配更少的資源?如果其他線程的時鐘用完了,我可以以某種方式使用Thread.Sleep來阻止表單事件嗎?

對於我所有令人沮喪的問題都有一個答案,是否有某種線程分析器可以用來幫助確定我的問題?我嘗試使用「管理堆棧資源管理器」,但不知何故,並不總是顯示我的應用程序有什麼線程。

任何關於此事的幫助都會對我有很大的幫助。

+0

你解決了這個問題嗎?我想我遇到過類似的事情,開啓 - 關閉 - 繪製窗口(即使通過其他進程)以某種方式拖延實時優先級線程。 –

+0

@EugeneRyabtsev不,這不是真的「解決」。我正在使用「BeginInvoke」和「線程池」。也沒有做出重大改進。在關鍵事件處理完成之後,直接在關鍵線索的某些部分進行睡眠有所幫助。所做的就是釋放不太重要的線程實際處理的週期時間。我發現如果一個不太關鍵的線程需要等待太久,它最終會影響更高優先級的線程。 –

回答

4

那麼這裏是一個開始:

Invoke(DelegatedDisplay, Result); 

這意味着你是導致後臺線程等待,直到UI線程實際執行繪圖操作,然後繼續。從線程的角度來看,這是永恆的。您可能希望異步更新調查的UI:

BeginInvoke(DelegatedDisplay, Result); 

這相當於告訴UI線程「當你有機會的話,執行此牽伸動作」,然後用你正在做的工作繼續進行。

您應該知道,這可能會導致線程安全問題,但使用Invoke時不會發生。例如,如果在UI嘗試繪製時後臺線程仍在修改Result,則可能會出現意外的競爭狀況。

Control.Invoke VS Control.BeginInvoke

+0

我的問題中顯示的「MyThread」是當前調用的內容,它的作用是從列表中刪除結果,然後進行通信,然後使用該結果執行調用。在這種情況下,我需要保護「結果」嗎?結果是我自己的類,所以我可以聲明一個新的結果作爲副本,然後在我的BeginInvoke中傳遞?我仍然很難知道指針何時被拋出,以及何時創建新數據。 –

+1

如果您在調用'BeginInvoke'後沒有修改「結果」或其中的任何內容,您應該沒問題。 –

+0

這可能是另一個愚蠢的問題,但是如果我多次調用一個聲明和啓動線程的函數,無論調用了多少次該函數,線程*都是單獨的線程,即使我將該函數調用兩次在線程完成一次之前。 –

1

使用編組技術,如InvokeBeginInvoke更新UI是問題的一部分。實際上,我很少使用封送處理操作進行UI和工作線程交互,因爲它不是很好的解決方案。坦率地說,在大多數這種性質的情況下,它可能(並且通常是)最糟糕的解決方案。

我通常所做的就是讓工作線程將其結果或進度發佈到共享數據結構,並讓UI線程在調整爲最適合該情況的時間間隔上使用System.Windows.Forms.Timer(或DispatcherTimer)進行輪詢在眼前。

下面是它的樣子。

public class YourForm : Form 
{ 
    private ConcurrentQueue<ResultContainer> results = new ConcurrentQueue<ResultContainer>(); 

    public UpdateTimer_Tick(object sender, EventArgs args) 
    { 
    // Limit the number of results to be processed on each cycle so that 
    // UI does not stall for too long. 
    int maximumResultsToProcessInThisBatch = 100; 

    ResultContainer result; 
    for (int i = 0; i < maximumResultsToProcessInThisBatch; i++) 
    { 
     if (!results.TryDequeue(out result)) break; 
     UpdateUiControlsHere(result); 
    } 
    } 

    private void WorkerThread() 
    { 
    while (true) 
    { 
     // Do work here. 
     var result = new ResultContainer(); 
     result.Item1 = /* whatever */; 
     result.Item2 = /* whatever */; 
     // Now publish the result. 
     results.Enqueue(result); 
    } 
    } 
} 

的事情是,人們一直是這樣編程自動使用InvokeBeginInvoke更新,他們忽略了更好的解決方案的用戶界面。它已經到了這些編組技術適合cargo cult programming的領域。我可能聽起來像是關於這個話題的一個破記錄,因爲我一直都在喋喋不休。我在上面使用的技術具有以下優點。

  • 它打破了編組操作強加的UI和工作線程之間的緊密耦合。
  • 工作線程不必等待來自UI線程的響應,就像Invoke那樣。
  • BeginInvoke一樣,沒有使UI消息隊列飽和的機會。
  • 您可以在UI和工作線程上獲得更高的吞吐量。
  • UI線程可以決定UI線程何時更新以及更新的頻率。
  • 你不必亂丟你的代碼(我的意思是完全字面上)與InvokeBeginInvoke調用。
  • 收編行動很貴。
  • 代碼最終看起來更優雅。

不是每次我需要的併發進程 花了我寶貴的時間推出一個新的線程?這應該是一個循環?我的循環被責備?

我會避免創建線程威利尼利。如果你可以讓線程運行在一個更好的循環中。

我可以給一個線程比別人更高的優先級,還是使用 Thread.Sleep我唯一的選擇?如果我確實分配了更高的線程優先級,我怎麼能確定其他線程能夠存活?

給你的工作線程更高的優先級可能會有助於在這種情況下。 Thread.Sleep(5)雖然不會睡5ms。它只是不這樣工作。順便說一下,您可以傳遞給Thread.Sleep的一些特殊值。

  • Thread.Sleep(0)產生任何處理器上具有相同或更高優先級的線程。
  • Thread.Sleep(1)產生任何處理器上的任何線程。

爲什麼簡單的表單事件會阻礙我的其他線程這麼多?有 有辦法給我的GUI線程分配一個較低的數量的 資源?如果 其他線程的時鐘用完了,我可以使用Thread.Sleep以某種方式阻止表單事件嗎?

這是因爲您使用的是Invoke。避免編組操作將有助於顯着幫助解耦線程。不要在UI線程上使用Thread.Sleep。 UI線程必須爲保持暢通,才能正常工作。如果你使用我上面提出的解決方案,那麼節制UI線程就容易多了。

+0

哇,好吧,我正在做一件事,因爲沒有在主線程上使用Thread.Sleep。我想我始終認爲,運行一個本質上輪詢列表的循環總是比我在需要時啓動更新的動作效率低。任何人都可以評論哪個解決方案更好嗎?如果我的GUI更新不重要,是否可以使用BeginInvoke?或者使用BeginInvoke會導致無處不在,即使在我的關鍵線程上? –

+0

經過一堆試驗和錯誤之後,我發現即使在刪除所有實例的BeginInvoke和Invoke之後,我的應用仍然被GUI所破壞。此外,我刪除了計時器,並且根本沒有更新GUI,而且我仍然會一段時間。必須有其他事情正在阻止我的重要線索。 –