博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
二、UI线程和界面卡死
阅读量:4945 次
发布时间:2019-06-11

本文共 1770 字,大约阅读时间需要 5 分钟。

上回说到,在Windows窗体程序中,响应Windows消息的线程就被称做Windows窗体程序的UI线程。UI线程还有一个重要的功能是创建和管理窗体和窗体中的各种控件,负责他们的实时刷新,如果UI线程在处理某个消息的时候耗时特别长,那么后续的消息就无法及时响应,看上去的感觉就是“界面卡死”了。此外,为了避免出现线程安全类的问题,UI控件是不能多线程访问的,一个backgroundworker线程直接去刷新控件,这是绝对不允许的,但这种需求又是客观存在的(比方说从数据库中获取数据后刷新到控件中)怎么办呢?

 
.Net给出的解决方案如下:
1,对控件,实现ISynchronizeInvoke接口
public interface ISynchronizeInvoke
{
        [HostProtection(SecurityAction.LinkDemand, Synchronization=true, ExternalThreading=true)]
        IAsyncResult BeginInvoke(Delegate method, object[] args);
        object EndInvoke(IAsyncResult result);
        object Invoke(Delegate method, object[] args);
        bool InvokeRequired { get; }
}
 
2,对非UI线程,如果要更新UI线程,那么把自己的操作封装到函数中,并声明委托作为Invoke或者BeginInvoke方法的参数。委托类似于回调函数的地址,因此非UI线程通过这两个方法就可以把需要调用的函数地址封送给界面线程。由于最终执行这个方法的是界面线程,从而避免了竞争条件,避免了不可预料的问题。
 
对非UI线程中调用Invoke或者BeginInvoke的区别在于,非UI线程调用Invoke后,非UI线程阻塞;而非UI线程调用BeginInvoke后,非UI线程不会阻塞。而不管是哪种调用,调用的委托方法都会在UI线程中执行。(在UI线程中调用控件的Invoke或者BeginInvoke方法是毫无意义的,仔细想想~~~)
 
使用Invoke完成一个委托方法的封送,就类似于使用SendMessage方法来给界面线程发送消息,是一个同步方法。也就是说在Invoke封送的方法被执行完毕前,Invoke方法不会返回,从而调用者线程将被阻塞。使用BeginInvoke方法封送一个委托方法,类似于使用PostMessage进行通信,这是一个异步方法。也就是该方法封送完毕后马上返回,不会等待委托方法的执行结束,调用者线程将不会被阻塞。但是调用者也可以使用EndInvoke方法或者其它类似WaitHandle机制等待异步操作的完成。但是在内部实现上,Invoke和BeginInvoke都是用了PostMessage方法,从而避免了SendMessage带来的问题。而Invoke方法的同步阻塞是靠WaitHandle机制来完成的。
 
如果你的后台线程在更新一个UI控件的状态后不需要等待,而是要继续往下处理,那么你就应该使用BeginInvoke来进行异步处理。如果你的后台线程需要操作UI控件,并且需要等到该操作执行完毕才能继续执行,那么你就应该使用Invoke。否则,在后台线程和UI线程共享某些状态数据的情况下,如果不同步调用,而是各自继续执行的话,可能会造成执行序列上的问题,虽然不发生死锁,但是会出现不可预料的显示结果或者数据处理错误。
 
回到标题上,Windows窗体程序如何避免界面卡死呢?
1,负责与用户交互的线程(以下简称为UI线程)应该保持顺畅,当UI线程调用的API可能引起阻塞时间超过30毫秒时(比如访问CD-ROM等速度超慢的外设、进行远程调用等等)就应该考虑使用多线程。对UI线程而言实际上就是:1、发出调用,2、立刻返回。
2,在Windows Form中使用多线程时,除了创建控件的线程以外,绝对不要在任何其他线程里面直接调用控件的成员,如果需要,请使用invoke或者BeginInvoke。

转载于:https://www.cnblogs.com/Yuxingzhi/p/4769450.html

你可能感兴趣的文章
高校表白APP-冲刺第四天
查看>>
outlook 设置163邮箱
查看>>
mysql优化——show processlist命令详解
查看>>
Solr服务器搭建
查看>>
画世界怎么用光影_世界绘画经典教程:水彩光影魔法教程
查看>>
win+rsync+php,跨平台的fswatch+rsync同步备份
查看>>
vue2 cdn 加载html,vue项目中使用CDN加载
查看>>
github.com访问慢解决
查看>>
转:哈夫曼树详解
查看>>
.Net Core Identity外面使用Cookie中间件
查看>>
C#中泛型之Dictionary
查看>>
Codeforces Round #376 (Div. 2)
查看>>
Codeforces 607D Power Tree 线段树 (看题解)
查看>>
写在人生的路上——2016年上半年总结
查看>>
C语言、C语言的起源以及类似C语言的编程语言的历史简直不要太漫长,我简单总结列表如下:...
查看>>
sp1.3-1.4 Neural Networks and Deep Learning
查看>>
SQL 将一个表中的所有记录插入到一个临时表中
查看>>
nmea协议
查看>>
js 中对象的特性
查看>>
hdoj3714【三分】
查看>>