Introduction to multithreading and parallel computing under. Net (9) on the basis of multi-thread programming in winform

Source: Internet
Author: User

In the previousArticleWe have introduced two types of timer and backgroundworker components. As mentioned above, we strongly recommend that you operate controls on the UI thread. Otherwise, it is easy to generate character problems. It can be seen that the two timer mentioned last time is based on threadpool, And the callback method runs on different threads of the UI thread. In this method, the control needs to be invoke or begininvoke. In fact, there is a third system. windows. forms. timer, which allows the callback event to be executed on the UI thread. Let's make an experiment and compare the system. windows. forms. timer and system. timers. timer. Create two tag controls on a form and then create two Timers:

 
PrivateSystem. Windows. forms.TimerTimer1 =NewSystem. Windows. forms.Timer();PrivateSystem. Timers.TimerTimer2 =NewSystem. Timers.Timer();PublicForm2 () {initializecomponent ();}

Double-click the form and write the following in the load event:Code:

This. Text =String. Concat ("#",Thread. Currentthread. managedthreadid );// Timer2.synchronizingobject = this;Timer2.interval = 1000; timer2.elapsed + =NewSystem. Timers.Elapsedeventhandler(Timer2_elapsed); timer2.enabled =True; Timer1.interval = 1000; timer1.tick + =NewSystem.Eventhandler(This. Timereffectick); timer1.enabled =True;

Then there are two timer processing methods:

  private void  timerw.tick ( Object  sender,  eventargs  E) {label1.text =  string . format ( "timer1: # {0} {1} {2}" ,  thread . currentthread. managedthreadid,  This . invokerequired,  datetime . now. tostring ();}  private void  timer2_elapsed ( Object  sender, system. timers.  elapsedeventargs  E) {label2.text =  string . format ( "timer2: # {0} {1} {2}" ,  thread . currentthread. managedthreadid,  This . invokerequired,  datetime . now. tostring () ;}

Run in non-debug modeProgramYou can see the following results:

Analyze the result

1) the ID of the UI hosting thread is 1.

2) system. Windows. Forms. timer runs on the UI thread and does not require invoke.

3) system. Timers. timer runs in a new thread and needs to be invoke

That is to say, if you run the program through debugging, the value assignment operation of the label2 control will fail. There are two ways to solve this problem:

1) Cancel comments timer2.synchronizingobject = This; make the callback method run on the UI thread (equivalent to system. Windows. Forms. Timer)

2) UI-related operations in the callback method use invoke or begininvoke

You can experiment with it. If the thread is blocked in the callback method, the UI is blocked and the interface stops responding. Therefore, if your callback method requires time-consuming operations, we recommend that you use a more flexible system. timers. timer, manual use of invoke or begininvoke, of course, if the callback method is mainly used to operate the UI, you can directly use system. windows. forms. timer.

For the backgroundworker component, we can think that we usually want background operations to run on the worker thread, and the progress report method to run on the UI thread. In fact, this is what it does, we can drag a backgroundworker in the toolbox to the Form Designer and add the following controls to the form:

It is a progressbar, two buttons, and two labels respectively. For backgroundworker, we can directly open its progress report and cancellation function in the Properties window:

Then add three event handling methods:

 Private void Backgroundworkerincludowork ( Object Sender, Doworkeventargs E ){ For ( Int I = 0; I <= 100; I + = 10 ){ If (Backgroundworker1.cancellationpending ){ For ( Int J = I; j> = 0; j-= 10) {backgroundworker1.reportprogress (j ); Thread . Sleep (500);} e. Cancel =True ; Return ;} Label1.text = String . Format ( "Worker: # {0} {1} {2 }" , Thread . Currentthread. managedthreadid, This . Invokerequired, Datetime . Now. tostring (); backgroundworker1.reportprogress (I ); Thread . Sleep (500);} e. Result = 100 ;} Private void Backgroundworker1_progresschanged ( Object Sender,Progresschangedeventargs E) {label2.text = String . Format ( "Progress: # {0} {1} {2 }" , Thread . Currentthread. managedthreadid, This . Invokerequired, Datetime . Now. tostring (); progressbar1.value = E. progresspercentage ;} Private void Backgroundworkerappsrunworkercompleted ( Object Sender, Runworkercompletedeventargs E ){ If (E. cancelled)MessageBox . Show ( "Cancelled" ); Else if (E. Error! = Null ) MessageBox . Show (E. Error. tostring ()); Else  MessageBox . Show (E. Result. tostring ());}

The two buttons are used to start and cancel background work respectively:

Private voidButton#click (ObjectSender,EventargsE ){If(! Backgroundworker1.isbusy) backgroundworker1.runworkerasync ();}Private voidButton2_click (ObjectSender,EventargsE ){If(Backgroundworker1.isbusy) backgroundworker1.cancelasync ();}

In the dowork event processing method and progresschanged event processing method, we output the managed thread ID on the corresponding tag. In the dowork event handling method, we also implement the rollback operation after canceling the task. After running the program in a non-debug mode and clicking the start button, the effect is as follows:

We can see that the progresschanged event processing method runs on the UI thread, while the dowork event processing method runs on the new thread, which meets our expectation.

Essentially, the progress report of backgroundworker is based on asyncoperation and is similar to the following:

 Asyncoperation Asyncoperation;Public Form4 () {initializecomponent (); This . Text = String . Concat ( "#" , Thread . Currentthread. managedthreadid); asyncoperation = Asyncoperationmanager . Createoperation ( Null );} Private void Button#click ( Object Sender, Eventargs E ){ New  Thread () => { For ( Int I = 0; I <= 100; I ++ = 10) {label1.text = String . Format ( "Worker: # {0} {1} {2 }" , Thread . Currentthread. managedthreadid, This . Invokerequired, Datetime . Now. tostring (); asyncoperation. Post ( New  Sendorpostcallback (J) => {label2.text = String . Format ("Progress: # {0} {1} {2 }" , Thread . Currentthread. managedthreadid, This . Invokerequired, Datetime . Now. tostring (); progressbar1.value = ( Int ) J ;}), I ); Thread . Sleep (500) ;}}) {isbackground = True }. Start ();}

Asyncoperation is encapsulation Based on synchronizationcontext. I personally think that asyncoperation and synchronizationcontext have similar effects as invoke and begininvoke, and there is not much space on asyncoperation and synchronizationcontext on msdn. Therefore, I prefer to directly use the original methods such as invoke and beininvoke without using backgroundworker.

The following sections will introduce the. NET asynchronous programming model APM.

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.