Invoke或者BeginInvoke的使用中无一例外地使用了委托Delegate,至于委托的本质请参考我的另一随笔:对事件的看法
 
一、Control提供了InvokeBeginInvoke机制?
问题的最主要的原因已dotnet程序众所周知的,我在此点笔墨再次记录到自己的日志,以便日后提醒一下自己。
1windows程序消息机制
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
一个委托来行同方法的步调用,也是提供的异步调用机制之一。但是Delegat
e.BeginInvoke方法是从ThreadPool取出一个线程来个方法,以得异步执行效果的。也就是,如果采用这种方式提交多个异委托,那么这用的序无法得到保。而且由于是使用线程池里面的线程来完成任,使用繁,会的性能造成影响。
Delegate.BeginInvoke也是一个委托方法封送到其它线程,从而通机制行一个方法。用者线可以在完成封送以后去继续它的工作。但是个方法封送到的最终执线程是运行从ThreadPool里面取的一个线程。
里需要正一个区,那就是Control上的异步调BeginInvoke并没有辟新的线程完成委托任,而是界面控件的所属线程完成委托任的。看来异操作就是辟新线程的法不一定准确。 
四、用Reflector察看一些相
1、Control.BeginInvoke and Control.Invoke
public IAsyncResult BeginInvoke(Delegate method, params object[] args)
{
    using (new MultithreadSafeCallScope())
    {
        return (IAsyncResult) this.FindMarshalingControl().MarshaledInvoke(this, method, args, false);
    }
}
public object Invoke(Delegate method, params object[] args)
{
    using (new MultithreadSafeCallScope())
    {
        return this.FindMarshalingControl().MarshaledInvoke(this, method, args, true);
    }
}
里的FindMarshalingControl方法通一个循向上回溯,从当前控件始回溯父控件,直到到最顶级的父控件,用它作封送象。例如,我们调用窗体上一个度条的Invoke方法封送委托,但是实际上会回溯到主窗体,通过这个控件象来封送委托。因主窗体是主线程消息列相的,主窗体的消息才能送到界面主线程消息列。
可以看到Invoke和BeginInvoke方法使用了同实现,只是MarshaledInvoke方法的最后一个参数不一
2、MarshaledInvoke
private object MarshaledInvoke(Control caller, Delegate method, object[] args, bool synchronous)

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。