对Windows窗体控件进行线程安全调用

MSDN文章: 如何:对Windows窗体控件进行线程安全调用我们应该使用异步委托来进行调用。 但为什么异步委托使呼叫安全?

Windows控件使用组件对象模型(COM)单线程单元(STA)模型,因为这些底层控件是单元线程的。 此外,许多控件使用消息泵进行许多操作。 此模型表示对每个控件的所有函数调用必须位于创建控件的同一线程上。 Invoke(和BeginInvoke和EndInvoke)编组方法调用正确的线程。

来自Bill Wagner的更有效的C#。 项目16.了解Windows窗体和WPF中的跨线程调用

你将调用control.BeginInvoke()或control.Invoke(),并且该方法将负责安全地在GUI分派线程中插入您的委托,因此稍后您的委托将在GUI线程中处理和执行,而不是你的主题

底线是:您不应该从创建控件的线程(UI /主线程)以外的线程更新UI控件。 否则,您可能会看到一些不可预测的行为。

如果需要从工作线程(主线程除外)更新UI,则需要在更新UI之前切换回UI线程。

文章建议使用

  • IsInvokeRequired (如果当前线程不是创建UI的IsInvokeRequired ,则返回true。)和Invoke(delegate) ,它在正确的/ UI线程上运行委托。 当您想要在异步进程之间更新UI时,这非常有用。 例如,更新UI上的进度。

  • BackgroundWorker对其DoWork事件异步执行注册处理程序。 在工作线程上,并将已注册的处理程序运行到调用线程上的RunWorkerCompleted事件。 如果要在异步任务完成更新UI,这是理想的选择。 例如,在UI上发布完成指示

因为,windows窗体控件是以这种方式设计的,所以只能从他们所拥有的线程中访问它们。 正确使用异步委托可以使呼叫安全。

给定问题的实际答案包含在给定MSDN文章的第二段中=)

对Windows窗体控件的访问本质上不是线程安全的。 如果您有两个或多个线程来操纵控件的状态,则可以强制控件进入不一致状态。 其他与线程相关的错误也是可能的,例如竞争条件和死锁。 确保以线程安全的方式访问控件非常重要。

您应该检查是否可以立即访问控制,没有间接(检查InvokeRequired属性),如果不能,则应该异步访问它(非常简化的说明:系统将等到它可以安全地访问控件)