当前位置:  开发笔记 > 开发工具 > 正文

在WinForms中,为什么不能从其他线程更新UI控件?

如何解决《在WinForms中,为什么不能从其他线程更新UI控件?》经验,为你挑选了3个好方法。

我确信这有一个好的(或至少是体面的)原因.它是什么?



1> Brian Ensink..:

我认为这是一个很好的问题 - 我认为需要一个更好的答案.

当然唯一的原因是框架中的某些东西不是非常线程安全的.

System.Windows.Forms中的每个控件上几乎每个实例成员都有"东西".

System.Windows.Forms中许多控件的MSDN文档,如果不是全部,说 "此类型的任何公共静态(在Visual Basic中共享)成员都是线程安全的.任何实例成员都不保证是线程安全的."

这意味着实例成员TextBox.Text {get; set;}不是可重入的.

使每个实例成员都是线程安全的,可能会引入大量应用程序不需要的开销.相反,.Net框架的设计者决定,并且我认为正确的是,应该将来自多个线程的对表单控件的访问同步的负担放在程序员身上.

[编辑]

虽然这个问题只是问"为什么"这里是链接到一篇解释"如何"的文章:

如何:在MSDN上对Windows窗体控件进行线程安全调用

http://msdn.microsoft.com/en-us/library/ms171728.aspx



2> John Sibly..:

因为你可以很容易地陷入僵局(以及其他问题).

例如,您的辅助线程可能正在尝试更新UI控件,但UI控件将等待由辅助线程锁定的资源被释放,因此两个线程最终都会等待彼此完成.正如其他人所评论的那样,这种情况并非UI代码所独有,而是特别常见.

在其他语言(如C++)中,您可以自由尝试执行此操作(没有像在WinForms中那样抛出异常),但是如果发生死锁,您的应用程序可能会冻结并停止响应.

顺便提一下,您可以轻松告诉UI线程您要更新控件,只需创建一个委托,然后在该控件上调用(异步)BeginInvoke方法,将其传递给您的委托.例如

myControl.BeginInvoke(myControl.UpdateFunction);

这相当于从工作线程执行C++/MFC PostMessage


我不确定为什么这个答案被接受了.这根本不是正确的答案.只要有多个线程,就会发生死锁.GUI程序中没有固有的东西使它们更容易发生.此外,即使您使用BeginInvoke(),它们也很容易发生.Brian Ensink的回答是正确的.
-1:等待锁定的资源不是问题。问题是竞态条件,这种竞态条件大量存在于非设计用于多线程环境的任何代码中。您甚至可以通过将[CheckForIllegalCrossThreadCalls](http://msdn.microsoft.com/zh-cn/library/system.windows.forms.control.checkforillegalcrossthreadcalls(VS.80).aspx)设置为false来进行检查,并观察死锁-免费操作,直到发生有趣的事情。

3> 小智..:

虽然听起来合理,但约翰的回答并不正确.事实上即使使用Invoke,你仍然不安全,不会遇到死锁情况.处理使用Invoke在后台线程上触发的事件时,甚至可能导致此问题.


真正的原因更多地与竞争条件有关,并在古代的Win32时代奠定了基础.我无法解释这里的细节,关键字是消息泵,WM_PAINT事件以及"SEND"和"POST"之间的细微差别.


更多信息可以在这里和这里找到.

推荐阅读
手机用户2402851155
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有