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. Here, the while loop uses the getmessage () method. 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. On the contrary, peekmessage () is usually used in some programs that require maximum CPU motion. For example, in some 3D games or strategy games, peekmessage () in this way, it will not be blocked by windows, so as to ensure 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 a Windows form control outside the thread, you need to use the invoke or begininvoke method and use a delegate to mail the call to the thread to which the control belongs for execution.
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
Both invoke and begininvoke require a principal 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.
Using invoke to complete the sending of a delegate method is similar to using the sendmessage method to send messages to the interface thread. It is a synchronous method. That is to say, the invoke method will not return until the invoke method is executed, and the caller thread will be blocked.
Use the begininvoke method to mail a delegate method, similar to using postmessage for communication, which 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. However, the caller can also use the endinvoke method or other similar waithandle mechanism to wait 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.
Let's take a look at the meaning of the two English words "send" and "Post": "send" means "send", while "Post" means "send.
Send: it is equivalent to a mail Officer who will hand over the parcel to the recipient and need the recipient's signature before the courier will pop up. In the message mechanism, that is, the system (Mailer) will directly send the received message (post office distribution) to a window (recipient ), this window must be processed (signed by the recipient) before returning. This is sendmessage.
Post: it is equivalent to a post office, a mail box, etc. After a good letter is written, the mail will be handed over to the post office, or delivered to the mail box. When and wherever it is sent, it will be handled by the post office, when we send a letter, we will not wait until it reaches the recipient's hand before returning home. In the message mechanism, that is to say, the system (we) sends the received messages to the application's message loop (equivalent to the mailbox), and then flashes, when to process this message (when to send an email), it depends on "service efficiency.
The difference is obvious: sendmessage messages are not in the queue, while postmessage needs to be queued.
However, it is worth noting that, even if one team is to be added and the other team is not involved, all messages are processed in the same way: All messages are processed in the System Call window process (the recipient responds)
Pretranslatemessage
We can use pretranslatemessage to pre-process messages. This method is not applicable. So, can we use the send and post messages for preprocessing?
The answer is no. If you are in Shenzhen and want to write a letter to the northeast, there are two ways to send the mail: 1. You can take the mail to the northeast, 2. Place the email in the post office and distribute it by the post office.
In 1st cases, sendmessage is used. At this time, who else can pre-process your messages?
In 2nd cases, it is postmessage. At this time, hey, in case of bad luck, the post office will use pretranslatemessage to intercept .....
Therefore, messages sent using sendmessage cannot be preprocessed using pretranslatemessage. Post can be used because it must pass through a "third party ".
3. usage issues
If your background thread does not need to wait after updating the status of a UI control, but needs to continue processing, you should use begininvoke for asynchronous processing.
If your background thread needs to operate the UI control and wait until the operation is completed to continue, you should use invoke. 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 invoke or begininvoke is required for an object to access the UI control during programming. 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. In addition, because the threads in the thread pool are used to complete tasks, frequent use 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.
Invoke and begininvoke