The previous article introduced the creation of multiple threads and the special characteristics of winform in multi-thread programming. This article introduces the classic asynchronous programming mode and Microsoft's implementation of it.
The Asynchronous Operation Model recommended by Microsoft is the event model, that is, the subthread notifies the caller of the working status through the event, that is, the observer mode in the design mode, it can also be seen as the extension of the thread class in the above text, and the call effect is similar
mythread thread = New mythread ()
thread. work += New threadwork (calculate)
thread. workcomplete += New workcomplete (displayresult)
calculate ( Object sender, eventargs E) {
....
}< br>
displayresult ( Object sender, eventargs E) {
...
}< br>
<Example 1>
This topic is already quite good.ArticleFor details, referCodeI will not go into details. I will mainly talk about Microsoft's implementation of this model.Backgroundworker
As mentioned in the previous article, the problem of control is that the execution Context of the above model is a problem in winform. In callback functions (such as displayresult in <Example 1> ), we have to use begininvoke to call the properties and methods of controls created by the UI thread,
For example, in the above net66 example
// Create thread object _ Task = New Newasynchui ();
// Upload progress bar modification event _ Task. taskprogresschanged + = New Taskeventhandler (ontaskprogresschanged1 );
// Updates the progress bar in the UI thread. Private Void Ontaskprogresschanged1 ( Object Sender, taskeventargs E)
{
If (Invokerequired) // Asynchronous call not on the UI thread {
Taskeventhandler tpchanged1 = New Taskeventhandler (ontaskprogresschanged1 );
This . Begininvoke (tpchanged1, New Object [] {Sender, e });
Console. writeline ( " Invokerequired = true " );
}
Else {Progressbar. Value = E. Progress;
}
}
<Example 2>
We can see that the function uses
If (invokerequired)
{... Begininvoke ....}
Else
{....}
This mode ensures that the methods can run under multiple threads and single threads. Therefore, the thread logic and interface logic are mixed together, so that the previous very simple task that only needs one sentence: progressbar. value = E. progress; it is very complicated. If the Thread class is provided as a public library and the requirement for writing events is relatively high, what is a better solution?
In fact, in. net2.0, Microsoft implemented this mode and created the backgroundworker class. He can solve the above problems. Let's take a look at his usage.
System. componentmodel. backgroundworker BW = New System. componentmodel. backgroundworker ();
// Define what needs to be done in the Child thread Bw. dowork + = New System. componentmodel. doworkeventhandler (bw_dowork );
// Define what needs to be done after execution Bw. runworkercompleted + = New System. componentmodel. runworkercompletedeventhandler (bw_runworkercompleted );
// Start execution Bw. runworkerasync ();
Static Void Bw_runworkercompleted ( Object Sender, system. componentmodel. runworkercompletedeventargs E)
{
MessageBox. Show ( " Complete " + Thread. currentthread. managedthreadid. tostring ());
}
Static Void Bw_dowork ( Object Sender, system. componentmodel. doworkeventargs E)
{
MessageBox. Show (thread. currentthread. managedthreadid );
}
<Example 3>
Note that I output the ID of the current thread in the two functions.ProgramWe are surprised to find that the callback function bw_runworkercompleted is actually running in the UI thread, that is to say, in this method, we no longer need to use invoke and begininvoke to call the control in winform. What's more strange to me is that if we run this code in consoleapplication, the thread ID output by bw_runworkercompleted is different from the main thread ID.
So how does backgroundworker implement cross-thread blocking?
After reading the code of this class, we find that it uses asyncoperation. Post (sendorpostcallback D, object Arg)
Using this function in winform enables sendorpostcallback to define the UI thread for being blocked and sent. Smart Bloggers can use this method to implement their own backgroundworker.
Continue to check and find that the key lies in the synccontext field of asyncoperation. This is an object of the synchronizationcontext type, and the POST method of this object implements sending. When I continue to view
Synchronizationcontext. Post method, which is simple and difficult to execute
Public Virtual VoidPost (sendorpostcallback D,ObjectState)
{
Threadpool. queueuserworkitem (NewWaitcallback (D. Invoke), State );
}
How can this happen? The thread pool in this province does not have the ability to send messages by thread.
I think the program behavior in winform and console programs is different, and the POST method of synchronizationcontext is a virtual method. I guess this method may be overwritten by the class inherited from it.
By querying msdn, we found that this class has two sub-classes, one of which isWindowsformssynchronizationcontextLet's take a look at the POST method of this class.
Public Override Void Post (sendorpostcallback D, Object State)
{
If ( This . Controltosendto ! = Null )
{
This . Controltosendto. begininvoke (D, New Object [] {State });
}
}
Haha, it is also a familiar begininvoke. The synchronizationcontext loaded by the console program and winform program is different, so the behavior is different. Through a simple test, we can see that the console program directly uses the base class (synchronizationcontext), and The winform program uses the POST method of windowsformssynchronizationcontext to mail the method call to the control thread.
Summary:
the colleague class also provides a progress change event that allows the user to terminate the thread. The function is comprehensive and the thread pool is used internally, in Chengdu, the resource consumption of a large number of threads can be avoided, and the issue of sending messages can be solved through synchronizationcontext. This makes the callback Event code logic simple and clear, and we recommend that you use it.