-
Invoke and BeginInvoke  (本文后面的源代码分析在我的博客园博客,就是此链接)

在Invoke或者BeginInvoke的使用中无一例外地使用了委托Delegate,至于委托的本质请参考我的另一随笔:对.net事件的看法。
 
一、为什么Control类提供了Invoke和BeginInvoke机制?
关于这个问题的最主要的原因已经是dotnet程序员众所周知的,我在此费点笔墨再次记录到自己的日志,以便日后提醒一下自己。
1、windows程序消息机制
Windows GUI程序是基于消息机制的,有个主线程维护着一个消息泵。这个消息泵让windows程序生生不息。

Windows GUI程序的消息循环

Windows程序有个消息队列,窗体上的所有消息是这个队列里面消息的最主要来源。这里的while循环使用了GetMessage()这个方法,这是个阻塞方法,也就是队列为空时方法就会被阻塞,从而这个while循环停止运动,这避免了一个程序把cpu无缘无故地耗尽,让其它程序难以得到响应。当然在某些需要cpu最大限度运动的程序里面就可以使用另外的方法,例如某些3d游戏或者及时战略游戏中,一般会使用PeekMessage()这个方法,它不会被windows阻塞,从而保证整个游戏的流畅和比较高的帧速。
这个主线程维护着整个窗体以及上面的子控件。当它得到一个消息,就会调用DispatchMessage方法派遣消息,这会引起对窗体上的窗口过程的调用。窗口过程里面当然是程序员提供的窗体数据更新代码和其它代码。
2、dotnet里面的消息循环
public static void Main(string[] args)
{
   Form f = new Form(); 
   Application.Run(f);
}
Dotnet窗体程序封装了上述的while循环,这个循环就是通过Application.Run方法启动的。
3、线程外操作GUI控件的问题
如果从另外一个线程操作windows窗体上的控件,就会和主线程产生竞争,造成不可预料的结果,甚至死锁。因此windows GUI编程有一个规则,就是只能通过创建控件的线程来操作控件的数据,否则就可能产生不可预料的结果。
因此,dotnet里面,为了方便地解决这些问题,Control类实现了ISynchronizeInvoke接口,提供了Invoke和BeginInvoke方法来提供让其它线程更新GUI界面控件的机制。
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; }
}
}
如果从线程外操作windows窗体控件,那么就需要使用Invoke或者BeginInvoke方法,通过一个委托把调用封送到控件所属的线程上执行。
二、消息机制---线程间和进程间通信机制
1、window消息发送
Windows消息机制是windows平台上的线程或者进程间通信机制之一。Windows消息值其实就是定义的一个数据结构,最重要的是消息的类型,它就是一个整数;然后就是消息的参数。消息的参数可以表示很多东西。
Windows提供了一些api用来向一个线程的消息队列发送消息。因此,一个线程可以向另一个线程的消息队列发送消息从而告诉对方做什么,这样就完成了线程间的通信。有些api发送消息需要一个窗口句柄,这种函数可以把消息发送到指定窗口的主线程消息队列;而有些则可以直接通过线程句柄,把消息发送到该线程消息队列中。

                                                     
 
用消息机制通信 
 
SendMessage是windows api,用来把一个消息发送到一个窗口的消息队列。这个方法是个阻塞方法,也就是操作系统会确保消息的确发送到目的消息队列,并且该消息被处理完毕以后,该函数才返回。返回之前,调用者将会被暂时阻塞。
PostMessage也是一个用来发送消息到窗口消息队列的api函数,但这个方法是非阻塞的。也就是它会马上返回,而不管消息是否真的发送到目的地,也就是调用者不会被阻塞。
2、Invoke and BeginInvoke


  
                                                        Invoke or BeginInvoke
 
Invoke或者BeginInvoke方法都需要一个委托对象作为参数。委托类似于回调函数的地址,因此调用者通过这两个方法就可以把需要调用的函数地址封送给界面线程。这些方法里面如果包含了更改控件状态的代码,那么由于最终执行这个方法的是界面线程,从而避免了竞争条件,避免了不可预料的问题。如果其它线程直接操作界面线程所属的控件,那么将会产生竞争条件,造成不可预料的结果。
使用Invoke完成一个委托方法的封送,就类似于使用SendMessage方法来给界面线程发送消息,是一个同步方法。也就是说在Invoke封送的方法被执行完毕前,Invoke方法不会返回,从而调用者线程将被阻塞。
使用BeginInvoke方法封送一个委托方法,类似于使用PostMessage进行通信,这是一个异步方法。也就是该方法封送完毕后马上返回,不会等待委托方法的执行结束,调用者线程将不会被阻塞。但是调用者也可以使用EndInvoke方法或者其它类似WaitHandle机制等待异步操作的完成。
但是在内部实现上,Invoke和BeginInvoke都是用了PostMessage方法,从而避免了SendMessage带来的问题。而Invoke方法的同步阻塞是靠WaitHandle机制来完成的。
3、使用场合问题
如果你的后台线程在更新一个UI控件的状态后不需要等待,而是要继续往下处理,那么你就应该使用BeginInvoke来进行异步处理。
如果你的后台线程需要操作UI控件,并且需要等到该操作执行完毕才能继续执行,那么你就应该使用Invoke。否则,在后台线程和主截面线程共享某些状态数据的情况下,如果不同步调用,而是各自继续执行的话,可能会造成执行序列上的问题,虽然不发生死锁,但是会出现不可预料的显示结果或者数据处理错误。
可以看到ISynchronizeInvoke有一个属性,InvokeRequired。这个属性就是用来在编程的时候确定,一个对象访问UI控件的时候是否需要使用Invoke或者BeginInvoke来进行封送。如果不需要那么就可以直接更新。在调用者对象和UI对象同属一个线程的时候这个属性返回false。在后面的代码分析中我们可以看到,Control类对这一属性的实现就是在判断调用者和控件是否属于同一个线程的。
三、Delegate.BeginInvoke
通过一个委托来进行同步方法的异步调用,也是.net提供的异步调用机制之一。但是Delegate.BeginInvoke方法是从ThreadPool取出一个线程来执行这个方法,以获得异步执行效果的。也就是说,如果采用这种方式提交多个异步委托,那么这些调用的顺序无法得到保证。而且由于是使用线程池里面的线程来完成任务,使用频繁,会对系统的性能造成影响。
Delegate.BeginInvoke也是讲一个委托方法封送到其它线程,从而通过异步机制执行一个方法。调用者线程则可以在完成封送以后去继续它的工作。但是这个方法封送到的最终执行线程是运行库从ThreadPool里面选取的一个线程。

这里需要纠正一个误区,那就是Control类上的异步调用BeginInvoke并没有开辟新的线程完成委托任务,而是让界面控件的所属线程完成委托任务的。看来异步操作就是开辟新线程的说法不一定准确。

Invoke and BeginInvoke 
文章出处:DIY部落(http://www.diybl.com/course/4_webprogram/asp.net/asp_netshl/2008612/125006.html)

转载于:https://www.cnblogs.com/vhtt/archive/2010/03/02/1676600.html

深入解析Invoke and BeginInvoke, 同步与异步解析相关推荐

  1. .NET 线程 Thread 进程 Process、线程池 pool、Invoke、begininvoke、异步回调、APM、EAP、TPL、aysnc、await

    windows系统是一个多线程的操作系统.一个程序至少有一个进程,一个进程至少有一个线程.进程是线程的容器,一个C#客户端程序开始于一个单独的线程,CLR(公共语言运行库)为该进程创建了一个线程,该线 ...

  2. javascript中BOM介绍、屏幕尺寸、历史记录、URL解析、计算机信息获取、定时器、三大系列及兼容代码、封装动画函数、同步和异步

    BOM介绍: BOM指的是浏览器对象模型,是用来操作浏览器的,例如浏览器弹窗.地址栏.滚动条等,浏览器顶级对象:window:页面中的所有内容都是属于window的,window可以省略:confir ...

  3. 同步、异步事件循环(宏任务、微任务「大厂真题解析」)

    引言:Js 是单线程,多任务执行时会触发进程阻塞问题.所以,Js 有两种任务的执行模式:同步和异步. 同步任务:运行在主线程,先于异步任务执行 异步任务:分为宏任务和微任务,微任务先于宏任务执行 微任 ...

  4. (转)Invoke and BeginInvoke

    Invoke and BeginInvoke 在Invoke或者BeginInvoke的使用中无一例外地使用了委托Delegate,至于委托的本质请参考我的另一随笔:对.net事件的看法. 一.为什么 ...

  5. 为什么Control类提供了Invoke和BeginInvoke机制

    在Invoke或者BeginInvoke的使用中无一例外地使用了委托Delegate,至于委托的本质请参考我的另一随笔:对.net事件的看法. 一.为什么Control类提供了Invoke和Begin ...

  6. 委托的Invoke 和 BeginInvoke 与Control的Invoke和BeginInvoke(转-因为写得很好)

    原文地址:http://www.cnblogs.com/worldreason/archive/2008/06/09/1216127.html Invoke and BeginInvoke Invok ...

  7. ASP.NET MVC涉及到的5个同步与异步,你是否傻傻分不清楚?[下篇]

    关于ASP.NET MVC对请求的处理方式(同步或者异步)涉及到的五个组件,在<上篇>中我们谈了三个(MvcHandler.Controller和ActionInvoker),现在我们来谈 ...

  8. c# Invoke和BeginInvoke 区别

    转自http://www.cnblogs.com/c2303191/articles/826571.html Control.Invoke 方法 (Delegate) :在拥有此控件的基础窗口句柄的线 ...

  9. C#的同步和异步调用方法

    同步和异步大家都明白什么意思,在这里不多介绍了. namespace ConsoleTest {class Program{static void Main(string[] args){Consol ...

  10. c# Invoke和BeginInvoke 区别详解

    Control.Invoke 方法 (Delegate):在拥有此控件的基础窗口句柄的线程上执行指定的委托. Control.BeginInvoke 方法 (Delegate) :在创建控件的基础句柄 ...

最新文章

  1. qq图片选择效果的处理
  2. 基于OpenCV的图像梯度与边缘检测!
  3. swift_043(Swift 懒加载(lazy) )
  4. java 8 stream 性能_java8中parallelStream性能测试及结果分析
  5. 我晕,代码又写错了,操你大爷
  6. DCOM 遇到错误“登录失败: 未知的用户名或错误密码
  7. 力扣-135 分发糖果
  8. shell第四次练习
  9. 安卓相机如何设置对焦模式
  10. java 总线_用于 Java 的服务总线库
  11. 正则表达式之提取数字
  12. VMware虚拟机无法自动获取IP地址的解决办法
  13. 【前端】页面适配?移动端适配屏幕的各种解决方案!
  14. StbM 和 Time Synchronization Over CAN and Ethernet(二) 以EthTSyn和StbM为例
  15. 请列举你所知道的Object类的方法并简要说明。
  16. 正则表达式在线测试一
  17. 卡片式轮播图 效果 实现
  18. 简析王者荣耀的匹配机制
  19. 统计学习:模型评估与选择--留出法(python实现)
  20. python爬取文献代码_爬取Pubmed文献及影响因子并尝试下载的脚本

热门文章

  1. 第一回 钟碧诚 被迫上屋顶
  2. bzoj 4571 美味 —— 主席树
  3. format not a string literal and no format arguments
  4. 从angularJS看MVVM
  5. 关于typedef的用法总结(转)
  6. window下git,TortoiseGit安装,以及和github托管项目
  7. 用DVD镜像离线安装Debian的软件包
  8. 《算法导论》第7章 快速排序 (四种变形)
  9. 简单使用Idea创建三层架构项目和数据库连接(使用原生ajax进行访问+ajax)
  10. 软件需求分析学习笔记