C # Delegate and Multithreading
In many cases, writing Windows programs requires multi-threading. In. net, use the following code to create and start a new thread.
Public void threadproc ();
Thread thread = new thread (New threadstart (threadproc ));
Thread. isbackground = true;
Thread. Start ();
However, in many cases, in the new thread, We need to interact with the UI. Net does not allow us to do this directly. Refer to the description in msdn:
"Windows Forms" uses the single-thread unit (STA) model, because "Windows Forms" are based on the Win32 window of the Local Machine, while the Win32 window is essentially a unit thread. The STA model means that a window can be created on any thread, but once the window is created
The thread cannot be switched, and all function calls to it must occur on the Creation thread. In addition to Windows Forms, classes in. NET Framework use free-threaded models.
The STA model requires that any method on the control that needs to be called from the non-creation thread of the control must be blocked and delivered (executed on it) to the creation thread of the control. The base class control provides several methods (invoke, begininvoke, and endinvoke) for this purpose ). Invoke
Generate synchronous method call; begininvoke generate Asynchronous Method call.
Controls in Windows Forms are bound to specific threads and do not have thread security. Therefore, if you call the control method from another thread, you must use one invoke method of the control to mail the call to the appropriate thread.
As we can see, we must call the invoke method, and begininvoke can be considered as the asynchronous version of invoke. The call method is as follows:
Public Delegate void outdelegate (string text );
Public void outtext (string text)
{
TXT. appendtext (text );
TXT. appendtext ("/T/N ");
}
Outdelegate = new outdelegate (outtext );
This. begininvoke (outdelegate, new object [] {text });
If we need to operate the UI in another thread, we need a function similar to outtext and a delegate to the function delegate. Of course, the following is a custom example ,.. Net has many other types of delegation, which can be directly used.
. For example: methodinvoker and eventhandler. The functions of these two types of delegation have a fixed appearance. methodinvoker is a void function () type delegate, while eventhandler is void function (object, eventargs)
Type delegation. The first parameter is not supported. The second parameter type and quantity are fixed. These two types of delegation can be conveniently called, but lack flexibility. Note that the object before begininvoke is this, that is, the main thread. I will introduce it now
Control. invokerequired, control is the base class of all controls. The msdn description of this attribute is:
Gets a value that indicates whether the caller must call the invoke method when calling the control method, because the call orientation is in a thread other than the thread where the control is created.
This attribute can be used to determine whether the invoke method must be called. It is useful when no thread has a control.
That is to say, by judging invokerequired, you can know whether to use delegate to call some methods of the current control, so you can modify the outtext function:
Public Delegate void outdelegate (string text );
Public void outtext (string text)
{
If (txt. invokerequired)
{
Outdelegate = new outdelegate (outtext );
This. begininvoke (outdelegate, new object [] {text });
Return;
}
TXT. appendtext (text );
TXT. appendtext ("/T/N ");
}
Note: The function is not returned here. If there is a returned result, you need to call invoke or endinvoke to obtain the returned result. Do not lose the returned value because of packaging. If the call is not completed, both invoke and endinvoke will cause blocking.
Now, if I have a thread function:
Public void threadproc ()
{
For (INT I = 0; I <5; I ++)
{
Outtext (I. tostring ());
Thread. Sleep (1000 );
}
}
If the number of loops is large or thread. Sleep (1000); is missing, your UI will definitely stop responding. Do you want to know the reason? Look at the object before begininvoke. That's right, that is, this, that is, the main thread. When your main thread continuously calls the outtext
Of course, the UI will stop responding.
The afxbeginthread function must be called to create a new thread in VC. The first parameter in this function is the address of the thread function, and the second parameter is a pointer type of lpvoid type, this parameter is passed to the thread function. There is no way
Then use this method to pass the parameter. We need to encapsulate the parameters passed to the thread and the thread function into a separate class, and then initialize the parameters required by the thread in the constructor of this class, then pass the thread functions of the instance to the Thread class structure.
Function. The code is roughly as follows:
Public class procclass
{
Private string procparameter = "";
Public procclass (string parameter)
{
Procparameter = parameter;
}
Public void threadproc ()
{
}
}
Procclass threadproc = new procclass ("Use thread class ");
Thread thread = new thread (New threadstart (threadproc. threadproc ));
Thread. isbackground = true;
Thread. Start ();
In this case, an intermediate class is required to pass the parameters required by the thread.
What if my thread needs parameters and interacts with the UI? You can modify the code:
Public class procclass
{
Private string procparameter = "";
Private form1.outdelegate Delg = NULL;
Public procclass (string parameter, form1.outdelegate Delg)
{
Procparameter = parameter;
This. Delg = Delg;
}
Public void threadproc ()
{
Delg. begininvoke ("use procclass. threadproc ()", null, null );
}
}
Procclass threadproc = new procclass ("Use thread class", new outdelegate (outtext ));
Thread thread = new thread (New threadstart (threadproc. threadproc ));
Thread. isbackground = true;
Thread. Start ();
This article from the csdn blog, reproduced please indicate the source: http://blog.csdn.net/niewq/archive/2010/05/19/5607821.aspx