C # Learning to modify UI controls in a worker thread----Invoke method

Source: Internet
Author: User
Tags dotnet message queue

Invoke and BeginInvoke reprint address: http://www.cnblogs.com/worldreason/archive/2008/06/09/1216127.html

In the use of Invoke or BeginInvoke no exception to the use of the delegate delegate, as to the nature of the Commission, please refer to my other essay: views on. NET events.
First, why does the control class provide the invoke and BeginInvoke mechanisms?

The main reason for this problem is already known to the dotnet programmers, I am here to pay a bit of ink to record their own log, in order to remind myself later.

1. Windows program Message mechanism

The Windows GUI program is message-based, and there is a main thread that maintains a message pump. This message pump keeps Windows programs alive.

Message loops for Windows GUI programs

Windows programs have a message queue, and all messages on the form are the most important source of messages inside this queue. Here the while loop uses the GetMessage () method, which is a blocking method, that is, when the queue is empty, the method is blocked, and the while loop stops moving, which avoids a program draining the CPU for no reason, making it difficult for other programs to get a response. Of course, in some programs that require maximum CPU movement, you can use another method, such as some 3d games or timely strategy games, usually use PeekMessage () This method, it will not be blocked by Windows, so as to ensure the smooth and relatively high frame rate of the whole game.

This main thread maintains the entire form and the child controls above it. When it gets a message, it calls the DispatchMessage method to dispatch the message, which causes a call to the window procedure on the form. The window procedure is of course the programmer provides the form data update code and other code.

2, dotnet inside the message loop

public static void Main (string[] args)

{

Form f = new form ();

Application.Run (f);

}

The Dotnet form program encapsulates the while loop, which is initiated by the Application.Run method.

3. Problems with the GUI control outside the thread operation

If you manipulate a control on a Windows Form from another thread, it competes with the main thread, causing unpredictable results or even deadlocks. So there is a rule in Windows GUI programming that the control's data can be manipulated only by creating the control's thread, otherwise unpredictable results can occur.

Therefore, in order to solve these problems conveniently, the control class implements the ISynchronizeInvoke interface and provides the Invoke and BeginInvoke methods to provide a mechanism for dotnet other threads to update GUI interface 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 are manipulating Windows Forms controls from outside the thread, you need to marshal the calls to the thread on which the control belongs by using the Invoke or BeginInvoke method.

II. Message Mechanism---Inter-threading and inter-process Communication mechanism 1, window message sending

The Windows Messaging mechanism is a thread on the Windows platform or one of the interprocess communication mechanisms. The Windows message value is actually a defined data structure, the most important is the type of the message, it is an integer, and then the parameters of the message. The parameters of a message can represent many things.

Windows provides some APIs for sending messages to a thread's message queue. Therefore, one thread can send a message to another thread's message queue to tell the other what to do, thus completing the communication between the threads. Some APIs send messages that require a window handle that can send messages to the main thread message queue of a specified window, while others can send messages to the threads message queue directly through the thread handle.

SendMessage is the Windows API, which is used to send a message to a window's message queue. This method is a blocking method, which means that the operating system will ensure that the message is actually sent to the destination message queue, and that the function is returned after the message has been processed. Before returning, the caller will be temporarily blocked.

PostMessage is also an API function used to send messages to a window message queue, but this method is non-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

Either the Invoke or BeginInvoke method requires a delegate object as a parameter. The delegate is similar to the address of the callback function, so the caller can then marshal the function address that needs to be called to the interface thread. In these methods, if you include code that changes the state of the control, it is the interface thread that eventually executes the method, which avoids the competitive conditions and avoids unforeseen problems. If other threads directly manipulate the control that the interface thread belongs to, then there will be a race condition, causing unpredictable results.

Using invoke to complete marshaling of a delegate method is similar to using the SendMessage method to send a message to the interface thread, which is a synchronous method. This means that the Invoke method does not return until the method of the invoke Marshal is executed, and the caller thread is blocked.

Marshaling a delegate method using the BeginInvoke method, similar to communicating using PostMessage, is an asynchronous method. That is, the method returns immediately after marshaling, does not wait for the execution of the delegate method to end, and the caller thread will not be blocked. But callers can also use the EndInvoke method or other similar WaitHandle mechanisms to wait for the completion of an asynchronous operation.

But in the internal implementation, both invoke and BeginInvoke use the PostMessage method, which avoids the problem of SendMessage. The synchronous blocking of the Invoke method is done by the WaitHandle mechanism.

3, the use of the occasion

If your background thread does not need to wait after updating the state of a UI control, but to continue working on it, then you should use BeginInvoke for asynchronous processing.

You should use invoke if your background thread needs to manipulate the UI control and needs to wait until the operation is complete before it can continue. Otherwise, in the case where the background thread and the main section thread share some state data, if the call is not synchronized and the execution continues, it may cause problems on the sequence of execution, although no deadlock occurs, but unexpected display results or data processing errors occur.

You can see that ISynchronizeInvoke has a property, invokerequired. This property is used when programming to determine whether an object needs to be marshaled using Invoke or BeginInvoke when accessing the UI control. You can update it directly if you don't need it. This property returns False when the caller object and the UI object belong to one thread. In the subsequent code analysis, we can see that the control class's implementation of this property is to determine whether the caller and the control belong to the same thread.

Third, Delegate.begininvoke

asynchronous invocation of a synchronous method through a delegate is also one of the asynchronous invocation mechanisms provided by. NET. But the Delegate.begininvoke method is to take a thread out of ThreadPool to execute this method to get an asynchronous execution effect. That is, if you commit multiple asynchronous delegates in this way, the order of these calls cannot be guaranteed. And because of the use of threads inside the thread pool to accomplish tasks, frequent use can have an impact on the performance of the system.

Delegate.begininvoke also tells a delegate method to marshal to another thread, thereby executing a method through an asynchronous mechanism. The caller thread can continue its work after the marshaling is complete. But the final thread of execution that this method marshals to is the one that the runtime picks from the ThreadPool.

One of the pitfalls here is that the asynchronous invocation of BeginInvoke on the control class does not open a new thread to complete the delegate task, but instead lets the interface control's owning thread complete the delegated task. It seems that asynchronous operations are not necessarily accurate in opening new threads.

Iv. use reflector to see some relevant code 1, Control.BeginInvoke and Control.Invoke
BeginInvoke (Delegate method, params object[] args)
{
using (new Multithreadsafecallscope ())
{
Return (IAsyncResult) this. Findmarshalingcontrol (). Marshaledinvoke (This, method, args, false);
}
}
Invoke (Delegate method, params object[] args)
{
using (new Multithreadsafecallscope ())
{
return this. Findmarshalingcontrol (). Marshaledinvoke (This, method, args, true);
}
}

The Findmarshalingcontrol method here loops up through a loop, backtracking the parent control from the current control until it finds the top-level parent control, which is used as the marshaling object. For example, we call the Invoke method of the previous progress bar on the form to marshal the delegate, but actually backtrack to the main form and marshal the delegate through the control object. Because the main form is related to the main thread message queue, messages sent to the main form can be sent to the interface's main thread message queue.

We can see that the invoke and BeginInvoke methods use the same implementation, except that the last parameter value of the Marshaledinvoke method is different.

2, Marshaledinvoke
Marshaledinvoke (Control caller, Delegate method, object[] args, bool synchronous)
{
num;
if (!this. ishandlecreated)
{
throw new InvalidOperationException (SR. GetString ("Errornomarshalingthread"));
}
if ((Activeximpl) this. Properties.getobject (propactiveximpl)) = null)
{
IntSecurity.UnmanagedCode.Demand ();
}
flag = false;
if (Safenativemethods.getwindowthreadprocessid (new HandleRef (this), this. Handle), out num) = = Safenativemethods.getcurrentthreadid ()) && synchronous)
{
Flag = true;
}
ExecutionContext = null;
if (!flag)
{
ExecutionContext = Executioncontext.capture ();
}
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). Handle), Threadcallbackmessage, IntPtr.Zero, IntPtr.Zero);
}
if (!synchronous)//If it is asynchronous, then return now
{
return entry;
}
if (!entry. iscompleted)//synchronous call is not over, block up and wait.
{
This. Waitforwaithandle (entry. AsyncWaitHandle);
}
if (entry.exception! = null)
{
Throw entry.exception;
}
return entry.retval;
}

What, did we finally see PostMessage? Marshaling is implemented through the Windows Messaging mechanism. The delegate method that needs to be marshaled is passed as a parameter of the message. There is no further explanation for the other code.

3, InvokeRequired
InvokeRequired
{
Get
{
using (new Multithreadsafecallscope ())
{
Ref2;
num;
if (this. ishandlecreated)
{
Ref2 = new HandleRef (this, this. Handle);
}
Else
{
wrapper = this. Findmarshalingcontrol ();
if (!wrapper. ishandlecreated)
{
return false;
}
Ref2 = new HandleRef (wrapper, wrapper. Handle);
}
Windowthreadprocessid = Safenativemethods.getwindowthreadprocessid (ref2, out num);
Currentthreadid = Safenativemethods.getcurrentthreadid ();
Return (Windowthreadprocessid! = Currentthreadid);
}
}

}

Finally see, this is to determine whether the Windows Forms thread and the current caller thread is the same, if the same is not necessary to marshal, direct access to the GUI control bar. Otherwise, do not be so straightforward to vindicate, you need to invoke or BeginInvoke matchmaking.

C # Learning to modify UI controls in a worker thread----Invoke method

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.