簡體   English   中英

WPF BackgroundWorker.RunWorkerAsync鎖定

[英]WPF BackgroundWorker.RunWorkerAsync lock

我想在WPF中使用BackgroundWorker實例來執行一些計算綁定操作。 可以從不同位置在一個確切的實例上調用RunWorkerAsync(...)方法。 如果在IsBusy為true時調用它,則拋出InvalidOperationException。 有人可以在以下代碼中的if(...)塊的檢查與RunWorkerAsync(1)的相應調用之間運行工作程序嗎?

    if(!_bgWorker.IsBusy) {
        _bgWorker.RunWorkerAsync(1);
    }

如果發生這種情況,會拋出InvalidOperationException嗎? 調用RunWorkerAsync(...)時是否應該總是像下面這樣編寫smth?

lock(_bgWorker) {
    if(!_bgWorker.IsBusy) {
        _bgWorker.RunWorkerAsync(1);
    }
}

鎖定關鍵字是一種實現我想要的好方法嗎?

假設此代碼是在UI線程上執行的,例如在KeyUp事件處理程序中:

private void someControl_KeyUp(object sender, KeyEventArgs e) {
    if(!_bgWorker.IsBusy) {
        _bgWorker.RunWorkerAsync(1);
    }
}

…並假設您只從UI線程啟動工作程序,那么我們可以確定IsBusy屬性在檢查時間和對RunWorkerAsync()的調用之間不會改變。

詳細說明這一點...

您要避免兩種有趣的情況:

  1. IsBusy為false,但在調用RunWorkerAsync()之前變為true。
  2. IsBusy為true,但在此方法返回之前變為false

第一種情況可能更危險,因為如果它已經啟動,那么您當然無法啟動它。 但是,你知道,第一個方案是不可能發生的,因為:a)您只開始從UI線程的工作人員,沒有別的可以在UI線程,直到此事件處理程序返回上執行,和b)假設你是以下所示的模式中這個答案 ,您啟動工作程序的唯一其他地方是在RunWorkerCompleted事件處理程序中,如果工作程序未運行(即IsBusy為false),則當然不會執行該操作。

第二種情況本身並不危險(即無例外),但是當然可能會導致工人在需要時不被運行。 但是您知道這種情況也不會發生,因為工作人員只能在RunWorkerCompleted事件處理程序完成后從IsBusy轉換為!IsBusy 與該事件處理程序一樣,由於該事件處理程序是在UI線程上執行的,因此您知道它在此事件處理程序運行時未運行,並且只有在該事件處理程序返回之前才能開始運行。

換句話說,需要執行所有這些代碼的UI線程充當方法之間的必要同步。 單線程無法與自己競爭。 該線程上發生的所有事情都必須一次發生。 即,一旦某個方法開始在該線程上執行,在第一個方法返回之前,其他任何方法都不能在同一線程上執行(或者,當然第一個方法調用了該方法,但這不是問題所在)。

注意:在C#中,請務必記住,某些類型的方法會在一次調用該方法時多次執行。 也就是說,他們確實會在完成之前返回。 但是,這些很容易注意到:迭代器方法甚至使用return關鍵字(即yield return )來表明這一點。 發生這種情況的另一個地方是async方法:在任何await語句中,該方法都可以返回(並且通常會返回),從而允許其他方法在UI線程上執行。

另一個例外是,如果在當前運行的方法返回之前調用了Application.DoEvents() (即,直接由該方法調用,或由它所調用的某些方法間接調用),這可能允許處理其他窗口消息,因此允許其他要調用的事件處理程序代碼。 這種行為,因為它違反了UI線程執行的常規約定,因此,我建議不要使用該方法(無論如何,它從來沒有真正需要過……它僅用作解決代碼中其他設計問題的技巧)。

這些例外均不適用於此,但我要確保提及它們,以使答案中的一般事實陳述不會被誤解且適用范圍太廣。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM