C # invoke and begininvoke

Source: Internet
Author: User
Tags dotnet

InUseWithout exceptionUseAs for the nature of delegation, please refer to another article: my views on. NET events.

I. Why does the control class provide the invoke and begininvoke mechanisms?

The main reason for this problem is already well known by dotnetprogrammers. I have recorded my own logs again here so that I can remind myself later.

1. Windows program message mechanism

The Windows GUI program is based on the message mechanism, and a main thread maintains a message pump. This message pump keeps Windows programs running.

 

Message loop in Windows GUI Program

 

 

 

A Windows program has a message queue. All messages in the form are the primary sources of messages in this queue. The while loop hereUseThe getmessage () method is used. This is a blocking method, that is, the method will be blocked when the queue is empty, so that the while loop stops motion, this avoids a program from exhausting the CPU for no reason, making it difficult for other programs to respond. Of course, in some programs that require maximum CPU movementUseOther methods, such as some 3D games or strategy games, usuallyUsePeekmessage (), which is not blocked by windows, ensures the smoothness and High Frame Rate of the entire game.

The main thread maintains the entire form and the child controls above. When it gets a message, it will call the dispatchmessage method to dispatch the message, which will cause the call to the Window Process on the form. In the window process, the form data update code and other code provided by the programmer are provided.

2. Message loop in DOTNET

Public static void main (string [] ARGs)

{

Form F = new form ();

Application. Run (f );

}

The DOTNET form program encapsulates the preceding while loop, which is started through the application. Run method.

3. Non-thread operations on GUI controls

If you operate controls on Windows forms from another thread, it will compete with the main thread, causing unpredictable results and even deadlocks. Therefore, Windows GUI programming has a rule that allows you to operate control data only by creating the control thread. Otherwise, unexpected results may occur.

Therefore, in DOTNET, to solve these problems easily, the control class implements the isynchronizeinvoke interface and provides the invoke and begininvoke methods to allow other threads to update GUI controls.

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 ;}

}

}

If you operate Windows Forms controls outside the thread, you needUseThe invoke or begininvoke method sends the call mails to the thread to which the control belongs for execution through a delegate.

Ii. Message Mechanism-Inter-thread and inter-process communication mechanism

1. Window message sending

Windows message mechanism is one of the threads or inter-process communication mechanisms on Windows. Windows message value is actually a defined data structure. The most important thing is the message type, which is an integer and then the message parameter. Message parameters can represent many things.

Windows provides APIs for sending messages to a thread message queue. Therefore, a thread can send messages to the Message Queue of another thread to tell the other thread what to do, thus completing inter-thread communication. Some APIs require a window handle to send messages. This function can send messages to the main thread message queue of the specified window, while some can directly use the thread handle, send messages to the thread message queue.

 

Communication by message mechanism

Sendmessage is a Windows API used to send a message to a window message queue. This method is a blocking method, that is, the operating system will ensure that the message is indeed sent to the destination message queue, and the function will return after the message is processed. The caller will be temporarily blocked before return.

Postmessage is also an API function used to send messages to the window message queue, but this method is not blocking. That is, it will return immediately, regardless of whether the message is actually sent to the destination, that is, the caller will not be blocked.

2. invoke and begininvoke

 

 

Invoke or begininvoke

The invoke or begininvoke method requires a delegate object as the parameter. The delegate is similar to the callback function address. Therefore, the caller can use these two methods to block the function address to the interface thread. If these methods contain code for changing the control status, the interface thread is used to avoid competition conditions and unexpected problems. If other threads directly operate on the control to which the interface thread belongs, competition conditions will be generated, resulting in unpredictable results.

UseInvoke completes the sending of a delegate method, which is similarUseThe sendmessage method is a synchronous method to send messages to the interface thread. That is to say, the invoke method will not return until the invoke method is executed, and the caller thread will be blocked.

UseThe begininvoke method sends a delegate method, which is similarUsePostmessage for communication. This is an Asynchronous Method. That is, the method will be returned immediately after the method is sent. It will not wait until the execution of the delegate method ends, and the caller thread will not be blocked. But the caller can alsoUseThe endinvoke method or other similar waithandle mechanism waits for the completion of asynchronous operations.

In terms of internal implementation, both invoke and begininvoke use the postmessage method to avoid problems caused by sendmessage. The synchronous blocking of the invoke method relies on the waithandle mechanism.

3,UseProblem

If your background thread does not need to wait after updating the status of a UI control, but needs to continue processing, you shouldUseBegininvoke for asynchronous processing.

If your background thread needs to operate the UI control and the execution can continue until the operation is completed, you shouldUseInvoke. Otherwise, if the background thread and the main cross-section thread share certain State data, if they do not call the data synchronously but continue to execute the data, the execution sequence may be faulty, although no deadlock occurs, unexpected display results or data processing errors may occur.

We can see that isynchronizeinvoke has an attribute called invokerequired. This attribute is used to determine whether an object needs to access the UI control during programming.UseInvoke or begininvoke. If you do not need it, you can directly update it. This attribute returns false when the caller object and UI object belong to the same thread. In the code analysis, we can see that the implementation of the control class for this attribute is to determine whether the caller and the control belong to the same thread.

3. Delegate. begininvoke

Asynchronous calling of synchronous methods through a delegate is also one of the asynchronous calling mechanisms provided by. net. However, the delegate. begininvoke method extracts a thread from the threadpool to execute this method to obtain the asynchronous execution effect. That is to say, if multiple asynchronous delegates are submitted in this way, the order of these calls cannot be guaranteed. And because it isUseThe threads in the thread pool to complete the task,UseFrequent, which may affect the system performance.

Delegate. begininvoke also refers to sending a delegate method to other threads, and thus executing a method through asynchronous mechanism. The caller thread can continue its work after the mail is completed. However, the final execution thread sent by this method is a thread selected by the Runtime library from the threadpool.

A misunderstanding needs to be corrected here, that is, the asynchronous call of the control class begininvoke does not open up a new thread to complete the delegate task, but rather enables the thread of the interface control to complete the delegate task. It seems that asynchronous operations are not necessarily accurate to open up new threads.

4. View related code with reflector

1. Control. begininvoke and control. Invoke

Public iasyncresult begininvoke (delegate method, Params object [] ARGs)

{

Using (New multithreadsafecallscope ())

{

Return (iasyncresult) This. findexternalingcontrol (). externaledinvoke (this, method, argS, false );

}

}

Public object invoke (delegate method, Params object [] ARGs)

{

Using (New multithreadsafecallscope ())

{

Return this. findexternalingcontrol (). externaledinvoke (this, method, argS, true );

}

}

The findexternalingcontrol method traces back the parent control from the current control until it finds the top-level parent control and uses it as the encapsulated object. For example, we call the invoke method of a progress bar on the form to block the delegate, but it will actually go back to the main form and use this control object to block the delegate. Because the main form is related to the main thread message queue, messages sent to the main form can be sent to the Interface main thread message queue.

We can see the invoke and begininvoke MethodsUseBut the last parameter value of the marshaledinvoke method is different.

2. marshaledinvoke

Private object marshaledinvoke (control caller, delegate method, object [] ARGs, bool synchronous)

{

Int num;

If (! This. ishandlecreated)

{

Throw new invalidoperationexception (Sr. getstring ("errornow.alingthread "));

}

If (activeximpl) This. properties. GetObject (propactiveximpl ))! = NULL)

{

Intsecurity. unmanagedcode. Demand ();

}

Bool flag = false;

If (safenativemethods. getwindowthreadprocessid (New handleref (this, this. Handle), Out num) = safenativemethods. getcurrentthreadid () & synchronous)

{

Flag = true;

}

Executioncontext = NULL;

If (! Flag)

{

Executioncontext = executioncontext. Capture ();

}

Threadmethodentry entry = new threadmethodentry (caller, method, argS, synchronous, executioncontext );

Lock (this)

{

If (this. threadcallbacklist = NULL)

{

This. threadcallbacklist = new Queue ();

}

}

Lock (this. threadcallbacklist)

{

If (threadcallbackmessage = 0)

{

Threadcallbackmessage = safenativemethods. registerwindowmessage (application. windowmessagesversion + "_ threadcallbackmessage ");

}

This. threadcallbacklist. enqueue (entry );

}

If (FLAG)

{

This. invokemarshaledcallbacks ();

}

Else

{// Finally found you, postmessage

Unsafenativemethods. postmessage (New handleref (this, this. Handle), threadcallbackmessage, intptr. Zero, intptr. Zero );

}

If (! Synchronous) // If asynchronous, return immediately

{

Return entry;

}

If (! Entry. iscompleted) // the synchronous call is not over. Block it and wait.

{

This. waitforwaithandle (entry. asyncwaithandle );

}

If (entry. Exception! = NULL)

{

Throw entry. exception;

}

Return entry. retval;

}

How do we finally see postmessage? Messages are sent through the windows message mechanism. The delegate method to be sent is passed as the message parameter. Other code is not explained here.

3. invokerequired

Public bool invokerequired

{

Get

{

Using (New multithreadsafecallscope ())

{

Handleref ref2;

Int num;

If (this. ishandlecreated)

{

Ref2 = new handleref (this, this. Handle );

}

Else

{

Control wrapper = This. findmarshalingcontrol ();

If (! Wrapper. ishandlecreated)

{

Return false;

}

Ref2 = new handleref (wrapper, wrapper. Handle );

}

Int windowthreadprocessid = safenativemethods. getwindowthreadprocessid (ref2, out num );

Int currentthreadid = safenativemethods. getcurrentthreadid ();

Return (windowthreadprocessid! = Currentthreadid );

}

}

}

Finally, we can see that this is to judge whether the Windows form thread and the current caller thread are the same. If it is the same, there is no need to mail it out. Visit this GUI control directly. Otherwise, you don't need to say so directly. You need to use invoke or begininvoke as the media.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.