为什么 Control.Invoke() 调用 PostMessage() 而不是 SendMessage()?
Why does Control.Invoke() calls PostMessage() instead of SendMessage()?
Control.Invoke()
调用 PostMessage()
,然后等待 UI 线程完成消息处理。那么为什么它不调用 SendMessage()
而不是(默认情况下等待 UI 线程完成消息处理)。
Control.Invoke() 是一个 危险的 方法,许多 .NET 程序员都用它来死锁他们的程序。因此,应该非常强烈地避免它。关闭 window 等简单的日常操作变得危险。您需要等到工作线程无法再调用,因为当线程保持 运行 但 UI 消失时没有任何好事发生。因此,您使用 AutoResetEvent 向线程发出信号并等待它完成。
当线程在错误的时间调用 Invoke() 时,这样的等待很可能使您的程序死锁。线程无法完成,因为它卡在 Invoke() 调用中,UI 线程无法为其提供服务,因为它卡在等待中。 A "deadly embrace",两个线程都无法取得进展,你的程序就会挂起。很难调试,因为它不可预测并且发生的频率不够高,只有当线程恰好同时调用 Invoke 时才会出错。
打破僵局需要知道 Invoke() 调用正在进行中,以便可以将其取消。当您使用 SendMessage() 时,它是不可知的。它阻塞的锁隐藏在 OS 中。我最近发布了 关于 SendMessage 问题的帖子,您在那里阅读的所有内容也适用于此处。
所以微软没有那样实现,他们使用了 PostMessage。他们向调用队列添加一个条目,调用 PostMessage 以唤醒 UI 线程,以便它查看该队列。特定于通过 BeginInvoke 调用,它们在队列条目中的 ManualResetEvent 上阻塞,当 UI 线程完成对委托目标的调用时发出信号。
现在他们可以采取一些措施来避免死锁,当 window 关闭时,它会查看调用队列并取消任何将 window 作为调用目标的队列。或者换句话说,当您使用 SendMessage 时不可见并导致死锁的锁现在变得可见并且可以被释放以打破死锁。
Control.Invoke()
调用 PostMessage()
,然后等待 UI 线程完成消息处理。那么为什么它不调用 SendMessage()
而不是(默认情况下等待 UI 线程完成消息处理)。
Control.Invoke() 是一个 危险的 方法,许多 .NET 程序员都用它来死锁他们的程序。因此,应该非常强烈地避免它。关闭 window 等简单的日常操作变得危险。您需要等到工作线程无法再调用,因为当线程保持 运行 但 UI 消失时没有任何好事发生。因此,您使用 AutoResetEvent 向线程发出信号并等待它完成。
当线程在错误的时间调用 Invoke() 时,这样的等待很可能使您的程序死锁。线程无法完成,因为它卡在 Invoke() 调用中,UI 线程无法为其提供服务,因为它卡在等待中。 A "deadly embrace",两个线程都无法取得进展,你的程序就会挂起。很难调试,因为它不可预测并且发生的频率不够高,只有当线程恰好同时调用 Invoke 时才会出错。
打破僵局需要知道 Invoke() 调用正在进行中,以便可以将其取消。当您使用 SendMessage() 时,它是不可知的。它阻塞的锁隐藏在 OS 中。我最近发布了
所以微软没有那样实现,他们使用了 PostMessage。他们向调用队列添加一个条目,调用 PostMessage 以唤醒 UI 线程,以便它查看该队列。特定于通过 BeginInvoke 调用,它们在队列条目中的 ManualResetEvent 上阻塞,当 UI 线程完成对委托目标的调用时发出信号。
现在他们可以采取一些措施来避免死锁,当 window 关闭时,它会查看调用队列并取消任何将 window 作为调用目标的队列。或者换句话说,当您使用 SendMessage 时不可见并导致死锁的锁现在变得可见并且可以被释放以打破死锁。