2017-04-12 83 views
3

考慮代碼:爲什麼WPF的Dispatcher.Invoke在主線程上運行時不會導致死鎖?

public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     private void button_Click(object sender, RoutedEventArgs e) 
     { 
      //System.Threading.Thread.CurrentThread = button.Dispatcher.Thread 
      button.Dispatcher.Invoke(() => button.Content = "1234"); 
     } 
    } 

當然,button_Click在主線程上運行。

我的理解是button.Dispatcher.Thread是主線程,Invoke()只有在線程未被阻塞時纔會被處理。但是,在這種情況下是不是主線程被阻塞?即主線程正在等待Dispatcher.Invoke()調用完成,Dispatcher.Invoke()正在等待主線程釋放。所以我期望在這裏陷入僵局,但它並沒有陷入僵局。

爲什麼?

P.S:我知道在這種情況下,我不需要Dispatcher.Invoke,我可以直接撥打button.Content = "1234"。我想了解爲什麼在這種情況下死鎖不會發生。

+0

你不需要該調度程序。正如你所說,你在使用ui線程;只需使用button.Content =「1234」; – GCamel

+0

@GCamel是的,我知道這一點。我試圖理解,爲什麼當我做dispatcher.Invoke(..) –

+0

時不會發生死鎖,所以實際上,你問一個問題,而不是一個解決方案...? WPF非常好...案例看起來很正常:你的button_click運行並將代理推送到你的應用程序的處理管道 – GCamel

回答

6

我相信你的誤解,可以根據各地的以下的思維過程:直到動作完成

「嗯,調用阻塞調用線程,它如何能在線程上執行的操作,如果線程被阻塞?」

如果我們看看源代碼內部,我們看到這個回調函數不僅在同一個線程上調用,而且直接調用Invoke方法。主線程未被阻止。

如果你看看調度的Reference Source頁面,你可以看到上面的Invoke方法的實現內的if聲明如下評論,有回調被稱爲內它:

// Fast-Path: if on the same thread, and invoking at Send priority, 
// and the cancellation token is not already canceled, then just 
// call the callback directly. 
if(!cancellationToken.IsCancellationRequested && priority == DispatcherPriority.Send && CheckAccess()) 
{ 
    /* snipped */ 

    callback(); 

    /* snipped */ 
} 

你在叫Dispatcher.Invoke主線程和方法通過立即調用它來處理。

*嗯,不是直接,但Invoke(Action)整個身體僅僅是上面的代碼是在方法調用

+0

謝謝。如果是這種情況,爲什麼建議在調用Invoke之前自己調用CheckAccess()? –

+0

你有建議的來源嗎?這是我聽到的第一個。 – Vassalware

+0

即使調度程序操作沒有立即調用(但爲了稍後執行而排隊),也不會有死鎖,因爲除UI線程外沒有其他線程。 – Clemens

相關問題