当前位置: 首页 > news >正文

C# Invoke和BeginInvoke的区别

上次在调试串口的时候,遇到了Invoke卡死的bug,第一次接触到了BeginInvoke,于是就找了找这两者的区别。

Invoke and BeginInvoke这篇文章介绍了windows程序消息机制,有兴趣可以看一下。
总结下来就是这么回事:

使用BeginInvoke方法封送一个委托方法,类似于使用PostMessage进行通信,这是一个异步方法。也就是该方法封送完毕后马上返回,不会等待委托方法的执行结束,调用者线程将不会被阻塞。但是调用者也可以使用EndInvoke方法或者其它类似WaitHandle机制等待异步操作的完成。

但是在内部实现上,Invoke和BeginInvoke都是用了PostMessage方法,从而避免了SendMessage带来的问题。而Invoke方法的同步阻塞是靠WaitHandle机制来完成的。

如果用代码来看的话,下面两种写法的效果是完全相同的。

			this.Invoke(new Action(() =>{textBox1.AppendText(s);}));
            IAsyncResult asyncResult = this.BeginInvoke(new Action(() =>{textBox1.AppendText(s);}));while (!asyncResult.AsyncWaitHandle.WaitOne()){}this.EndInvoke(asyncResult);   
			IAsyncResult asyncResult = this.BeginInvoke(new Action(() =>{textBox1.AppendText(s);}));while (!asyncResult.IsCompleted){}this.EndInvoke(asyncResult);   

假如代理通知的事情一直没有完成,使用Invoke就会一直阻塞再这里。

考虑到asyncResult.IsCompleted不具有阻塞性,即cpu会一直执行类似while(true)的语句,程序是真的退不出去。而asyncResult.AsyncWaitHandle.WaitOne()还具有多个重载:

		//// 摘要: //     阻止当前线程,直到当前 System.Threading.WaitHandle 收到信号。//// 返回结果: //     如果当前实例收到信号,则为 true。 如果当前实例永远收不到信号,则 System.Threading.WaitHandle.WaitOne(System.Int32,System.Boolean)//     永不返回。//// 异常: //   System.ObjectDisposedException://     当前实例已被释放。////   System.Threading.AbandonedMutexException://     线程退出时未释放互斥体,等待过程已终止。 在 Windows 98 或 Windows Millennium Edition 中不引发此异常。////   System.InvalidOperationException://     当前实例是另一个应用程序域中的 System.Threading.WaitHandle 的透明代理。public virtual bool WaitOne();//// 摘要: //     阻止当前线程,直到当前 System.Threading.WaitHandle 收到信号,同时使用 32 位带符号整数指定时间间隔。//// 参数: //   millisecondsTimeout://     等待的毫秒数,或为 System.Threading.Timeout.Infinite (-1),表示无限期等待。//// 返回结果: //     如果当前实例收到信号,则为 true;否则为 false。//// 异常: //   System.ObjectDisposedException://     当前实例已被释放。////   System.ArgumentOutOfRangeException://     millisecondsTimeout 是一个非 -1 的负数,而 -1 表示无限期超时。////   System.Threading.AbandonedMutexException://     线程退出时未释放互斥体,等待过程已终止。 在 Windows 98 或 Windows Millennium Edition 中不引发此异常。////   System.InvalidOperationException://     当前实例是另一个应用程序域中的 System.Threading.WaitHandle 的透明代理。public virtual bool WaitOne(int millisecondsTimeout);

参考c#线程之异步委托begininvoke、invoke、AsyncWaitHandle.WaitOne 、异步回调和BeginInvoke和EndInvoke方法两篇博客,可以使用WaitOne(int millisecondsTimeout)方法。
如果invoke没有返回,则阻塞500ms后,WaitOne()函数返回false,可以做异常处理。
如果500ms以内返回,正常结束Invoke。

            IAsyncResult asyncResult = this.BeginInvoke(new Action(() =>{textBox1.AppendText(s);}));if (asyncResult.AsyncWaitHandle.WaitOne(500)){this.EndInvoke(asyncResult);}else{MessageBox.Show("返回超时");}

通过一个委托来进行同步方法的异步调用,也是.net提供的异步调用机制之一。但是Delegate.BeginInvoke方法是从ThreadPool取出一个线程来执行这个方法,以获得异步执行效果的。也就是说,如果采用这种方式提交多个异步委托,那么这些调用的顺序无法得到保证。而且由于是使用线程池里面的线程来完成任务,使用频繁,会对系统的性能造成影响。
Delegate.BeginInvoke也是讲一个委托方法封送到其它线程,从而通过异步机制执行一个方法。调用者线程则可以在完成封送以后去继续它的工作。但是这个方法封送到的最终执行线程是运行库从ThreadPool里面选取的一个线程。
这里需要纠正一个误区,那就是Control类上的异步调用BeginInvoke并没有开辟新的线程完成委托任务,而是让界面控件的所属线程完成委托任务的。看来异步操作就是开辟新线程的说法不一定准确。

在这里插入图片描述
实际也测试过,在Action中加Thread.Sleep,会让UI线程1s响应一次,因为这里的BeginInvoke是Control.Invoke,并不是单独开一个线程去执行的Action。

http://www.xdnf.cn/news/834319.html

相关文章:

  • python中shutil.copyfile的用法_python处理文件和文件的方法(shutil,filecmp ,MD5,tarfile,zip)...
  • FTP地址大全
  • GoLang之interface
  • PostgreSQL学习总结(13)—— PostgreSQL 目录结构与配置文件 postgresql.conf 详解
  • 骡友们推荐的各个学习英文网站的汇总
  • 【Unity插件】最多的插件合集
  • CDMA2000简介
  • Scanner类中next()、nextInt()和nextLine()方法的区别
  • Windows Server 2008 各版本介绍
  • Java——防止SQL注入的几种策略
  • 网络安全方面有哪些认证,看完这篇你就知道了
  • mscorsvw.exe是什么
  • 法国国际广播电台官方网站
  • Linux入门的基础知识点
  • Jlink 烧写文件到 nandflash norflash
  • [密码学]OpenSSL实践篇
  • 什么是透明加密?如何用透明加密保护数据安全?
  • C语言:lseek函数-----改变文件偏移量
  • 正则表达式(python)
  • WeakHashMap
  • 不会前端也可以看得懂的3种DIV+CSS布局技术
  • 常见功能测试点的测试用例大全(干货)
  • php文件777访问权限,奇怪的php文件读写权限问题【全777+apache:apache】?
  • C语言-static的用法
  • 网络安全人士必备的30个安全工具
  • RedHat 下载地址
  • 查看iOS中app的bundleId
  • 国标二阶段VIR消息集调试总结
  • 深度剖析单点登录流程原理,从0带你手写一个SSO
  • 【C语言】每日一代码:最大公约数