为什么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"
。我想了解为什么在这种情况下死锁不会发生。
我相信你的误解,可以根据各地的以下的思维过程:直到动作完成
“嗯,调用阻塞调用线程,它如何能在线程上执行的操作,如果线程被阻塞?”
如果我们看看源代码内部,我们看到这个回调函数不仅在同一个线程上调用,而且直接调用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)
整个身体仅仅是上面的代码是在方法调用
谢谢。如果是这种情况,为什么建议在调用Invoke之前自己调用CheckAccess()? –
你有建议的来源吗?这是我听到的第一个。 – Vassalware
即使调度程序操作没有立即调用(但为了稍后执行而排队),也不会有死锁,因为除UI线程外没有其他线程。 – Clemens
你不需要该调度程序。正如你所说,你在使用ui线程;只需使用button.Content =“1234”; – GCamel
@GCamel是的,我知道这一点。我试图理解,为什么当我做dispatcher.Invoke(..) –
时不会发生死锁,所以实际上,你问一个问题,而不是一个解决方案...? WPF非常好...案例看起来很正常:你的button_click运行并将代理推送到你的应用程序的处理管道 – GCamel