为什么WPF的Dispatcher.Invoke在主线程上运行时不会导致死锁?

问题描述:

考虑代码:为什么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

我相信你的误解,可以根据各地的以下的思维过程:直到动作完成

“嗯,调用阻塞调用线程,它如何能在线程上执行的操作,如果线程被阻塞?”

如果我们看看源代码内部,我们看到这个回调函数不仅在同一个线程上调用,而且直接调用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