Control.Invoke()与Control.BeginInvoke() [英] Control.Invoke() vs. Control.BeginInvoke()

查看:205
本文介绍了Control.Invoke()与Control.BeginInvoke()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我想为我的语法不好而道歉,因为英语不是我的母语.

据我了解:

Control.Invoke(delegated_method)//在创建控件的线程上执行
女巫握住它的手柄,通常这将是winform应用程序的主线程.

Control.BeginInvoke(delegated_method//在threadPool线程上异步执行.

根据msdn

在创建控件的基础句柄的线程上异步执行委托."

我的问题:

我是否了解beginInvoke会像处理线程池那样对待主线程,并在有机会"时在主线程上执行委托的方法?

女巫提出了另一个问题,
是否可以不在主线程上创建控件?
如果可以的话,有人可以给我举个例子吗?

first of all,i would like to apologize for my bad grammar since English is not my native tongue.

To my understanding :

Control.Invoke(delegated_method) // Executes on the thread wich the control was created on
witch holds its handle ,typically this would be the main thread of a winform application .

Control.BeginInvoke(delegated_method // Executes asynchronously on a threadPool Thread .

according to msdn

"Executes a delegate asynchronously on the thread that the control''s underlying handle was created on."

My QUESTION :

am i to understand that beginInvoke treats the main thread in this matter as it would the thread pool , and execute the delegated method on the main thread when it "gets a chance" ?

another question witch is raised ,
is it possible to create a control not on the main thread ?
if so could some one give me an example

推荐答案

没什么.

首先,您所说的主线程通常更称为UI线程.

Control.InvokeControl.BeginInvoke在任何线程中工作.该功能对线程的起源完全不敏感:它可以是UI线程,通过System.Threading.Thread构造函数创建的线程,来自线程池的线程或由System.ComponentModel.BackgroundWorker创建的线程.
该API的目的是在UI线程上分派委托实例的调用.如果在UI线程中完成了对Control.InvokeControl.BeginInvoke的调用,则将立即调用该委托.由于在这种情况下调用机制是多余的,因此可以通过检查谓词属性Control.InvokeRequired避免这种情况.如果不需要调用机制,则首选定期调用控件的方法或属性.仅对于可以从不同线程完成的某些调用的泛化才需要此谓词:有时在UI线程中,有时不需要.在许多情况下,开发人员可以肯定地知道只能从非UI线程调用委托.在这种情况下,不需要Control.InvokeRequired,因为无论如何都应使用调用.

现在,UI库(System.Windows.Forms和WPF)的设计方式使得对所有UI控件和Application的所有调用都不应直接完成,而应分派给UI线程.对于Forms和FPW,此功能还有另一个接口,具有高度扩展的功能:System.Windows.Threading.Dispatcher,它也具有InvokeBeginInvoke方法,有几个重载. Dispatcher的实例可以使用静态属性System.Windows.Threading.Dispatcher.CurrentDispatcher获得(此属性可以实例化新实例,也可以使用以前创建的Dispatcher实例).

现在,Dispatcher方法,Control.InvokeControl.BeginInvoke使用相同的机制向UI线程分配委托:委托实例和实际调用参数的实例放入某个队列,由WPF或System.Windows.Forms UI线程.在主UI周期中,此数据从队列中删除,并用于进行实际的调用.每个线程实例都有调用列表.调用列表的每个元素都封装了委托入口点,用于访问该方法的声明类的实例的this参数(如果该方法是非静态的)和所有调用参数的实例.所有这些数据都用于实际呼叫.

现在我们来了解InvokeBeginInvoke之间的区别.对于Invoke,从调用获得的返回值将返回给Invoke的调用者.这意味着线程同步正在阻止正在调用的非UI线程.

相比之下,BeginInvoke会立即返回类型为System.IAsyncResult的结果,因此该调用以非阻塞方式进行调用.在大多数情况下,尤其是在不需要返回结果的情况下,应使用此调用方法.一个典型的示例:获取UI线程以显示来自非UI线程状态的通知.

如果需要BeginInvoke的返回结果,则情况非常复杂,因为结果尚未立即准备好,因此无论如何都需要某种等待.在标准帮助文档中没有很好地记录该文档.基本上,有三种方法可以在以后获取调用结果,其中一种是调用阻塞EndInvoke.您可以在此处找到更多详细信息和建议: http://support.microsoft.com/kb/315582 [ ^ ].

有一个非常普遍的误解,即调用机制可以通过Dispacher与任何线程一起使用.这不是真的. Dispatcher确实也可用于非UI应用程序,但是使用InvokeBeginInvoke,如果没有活动的UI线程,它不会做任何有用的事情!对这些方法的调用等效于在同一线程上的委托的常规调用.

是否可以在任何线程上使用类似的机制?否,但是当队列的元素是委托实例时,可以使用阻塞队列在专门编写的自定义线程上完成.可以在我的提示/技巧文章中找到带有用法示例的完整代码:
Nothing like that.

First of all, what you call main thread is more usually called UI thread.

Control.Invoke and Control.BeginInvoke work in any thread. The functionality is completely insensitive to the origin of the thread: it can be UI thread, a thread created through System.Threading.Thread constructor, a thread from the thread pool or a thread created by System.ComponentModel.BackgroundWorker.

The purpose of this API is to dispatch a call of the delegate instance on the UI thread. If the call to Control.Invoke or Control.BeginInvoke is done in UI thread, the delegate will be called immediately. As the invocation mechanism is redundant in this case, this can be avoided by checking the predicate property Control.InvokeRequired. If invocation mechanism is not required, regular call of control''s method or property is preferred. This predicate is only needed for some generalization of some call which can be done from different threads: sometimes in UI thread, sometimes not. In many cases the developer knows for sure that the delegate will be called on from non-UI thread only; in this case Control.InvokeRequired is not needed, as invocation should be used anyway.

Now, UI libraries (both System.Windows.Forms and WPF) are designed in such a way that all calls to all UI controls and Application should never be done directly, but should dispatched to the UI thread. There is another interface to this functionality common for Forms and FPW, with highly extended functionality: System.Windows.Threading.Dispatcher, it also has Invoke and BeginInvoke methods, several overloads. The instance of Dispatcher can be obtained using the static property System.Windows.Threading.Dispatcher.CurrentDispatcher (this property either instantiates new instance or use previously created instance of Dispatcher).

Now, Dispatcher methods, Control.Invoke and Control.BeginInvoke use the same mechanism of dispatching a delegate to the UI thread: the delegate instance and instances of actual calling parameters are put to some queue, which is read by the WPF or System.Windows.Forms UI thread. In main UI cycle, this data is removed from the queue and used to make an actual call. Each thread instance has the invocation list; each element of invocation list encapsulates delegate entry point, this parameter used to access the instance of the declaring class of the method (if the method is non-static) and all instances of call parameters. All this data is used for the actual call.

Now we came to the difference between Invoke and BeginInvoke. For Invoke, return value obtained from the call is returned to caller of Invoke. It means that the thread synchronization is blocking for the calling non-UI thread.

In contrast, BeginInvoke returns immediately with the result of the type System.IAsyncResult, so this call itself in non-blocking. This invocation method should be used in most cases, especially when return result is not needed; a typical example: getting UI thread showing notification from non-UI thread status.

If return result from BeginInvoke is needed, the situation is pretty complex, as result is not ready immediately, so some kind of wait is needed anyway. It is not well documented in standard help documentation. Basically, there are three ways of obtaining the result of invocation later, one of them is calling blocking EndInvoke. You can find further details and recommendations here: http://support.microsoft.com/kb/315582[^].

There is a very popular misconception that the invocation mechanism can be used with any thread through Dispacher. This is not true. The Dispatcher really works for non-UI applications as well, but is Invoke or BeginInvoke is used, it does not do anything useful if there is no active UI thread! The call to those method is equivalent to regular call of the delegate on the same thread.

Is is possible to use the similar mechanism on any thread? No, but it can be done on specially written custom thread using a blocking queue, when the elements of the queue are delegate instances. A complete code with usage samples can be found in my Tips/Tricks article: Simple Blocking Queue for Thread Communication and Inter-thread Invocation[^]. If you look at the source code, it will give you a good idea on how UI thread invocation mechanism works.

—SA


这篇关于Control.Invoke()与Control.BeginInvoke()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆