In multi-threaded applications, we have some common requirements, such as scheduled tasks or long-time tasks, progress can be displayed during the execution of this task (you can think of a new thread to achieve this requirement to avoid blocking UI updates ). Ready-made components are provided for these applications. net.
First, let's take a look at the timer component of system. Threading. It provides a method to regularly execute a task:
Threadpool . Setminthreads (2, 2 ); Threadpool . Setmaxthreads (4, 4 ); Timer Timer = New Timer (State) => { Int A, B; Threadpool . Getavailablethreads ( Out A, Out B ); Console . Writeline ( String . Format ( "({0}/{1}) #{2 }:{ 3 }" , A, B, Thread . Currentthread. managedthreadid, Datetime . Now. tostring ( "Mm: SS" )));}, Null , 2000,100 0 ); Console . Writeline ( Datetime . Now. tostring ( "Mm: SS" )); Thread . Sleep (5000 ); Console . Writeline ("Change ()" ); Timer. Change (3000,500 ); Thread . Sleep (5000 ); Console . Writeline ( "Dispose ()" ); Timer. Dispose (); Thread . Sleep (5000 ); Console . Writeline ( Datetime . Now. tostring ( "Mm: SS" ));
This sectionCodeThe running result is as follows:
We can see that:
1) In the timer constructor, the first parameter is the method to be periodically executed. This method accepts a state parameter, and the second parameter is the state parameter, the third parameter is the delay milliseconds before the first callback method call. The fourth parameter is the interval of milliseconds between the execution methods.
2) from the results, we can see that the first callback method is executed after 2 seconds, and then executed every second. Then we call the change () method to set the delay time to 3 seconds, set the interval to 500 milliseconds. It can be seen that timer executes a new callback 3 seconds after the last callback is completed, and then runs the callback once every 500 milliseconds.
3) Finally, the dispose () method is executed. After the last callback is completed, Timer no longer calls the callback method.
4) In the callback method, we output the available threads of the thread pool. We can see that timer is based on the thread pool, that is, timer is based on the background thread.
. Net also provides system. Timers. Timer, which encapsulates and enhances system. Threading. Timer:
System. Timers. Timer Timer2 = New System. Timers. Timer (); Timer2.elapsed + = New System. Timers. Elapsedeventhandler (Timer2_elapsed); timer2.interval = 1000; Console . Writeline ( "Start ()" ); Timer2.start (); Console . Writeline ( Datetime . Now. tostring ( "Mm: SS" )); Thread . Sleep (5000 ); Console . Writeline ( "Stop ()" ); Timer2.stop (); Thread . Sleep (5000 ); Console . Writeline ( "Change Interval and start ()" ); Timer2.interval = 500; timer2.start (); Thread . Sleep (5000 ); Console . Writeline ("Dispose ()" ); Timer2.dispose (); Thread . Sleep (5000 ); Console . Writeline ( Datetime . Now. tostring ( "Mm: SS" ));
Static voidTimer2_elapsed (ObjectSender, system. Timers.ElapsedeventargsE ){IntA, B;Threadpool. Getavailablethreads (OutA,OutB );Console. Writeline (String. Format ("({0}/{1}) #{2 }:{ 3 }", A, B,Thread. Currentthread. managedthreadid, E. signaltime. tostring ("Mm: SS")));}
(Suppose we still set the thread pool with a minimum of 2 threads and a maximum of 4 threads)
The result of this Code is as follows:
From the running result, we can see:
1) Because system. Timers. Timer encapsulates system. Threading. Timer, it is still based on the thread pool.
2) by default, timer is stopped. After starting, you need to wait for an interval before executing the callback method.
Finally, let's take a look at backgroundworker. It provides encapsulation of the Application for executing a task, updating progress on the UI, and first defines a static backgroundworker:
StaticBackgroundworkerBW =NewBackgroundworker();
Then write the following test code:
Bw. workerreportsprogress = True ; BW. workersuppscanscancellation = True ; BW. progresschanged + = New Progresschangedeventhandler (Bw_progresschanged); BW. runworkercompleted + = New Runworkercompletedeventhandler (Bw_runworkercompleted); BW. dowork + =New Doworkeventhandler (Bw_dowork); BW. Disposed + = New Eventhandler (Bw_disposed ); Autoresetevent Are = New Autoresetevent ( False ); Console . Writeline ( Datetime . Now. tostring ( "Mm: SS" ); BW. runworkerasync (are ); Thread . Sleep (2000); Are. Set ();Thread . Sleep (2000 ); Console . Writeline ( "Cancelasync ()" ); BW. cancelasync (); While (Bw. isbusy) Thread . Sleep (10); BW. Dispose ();
In this Code, we:
1) set backgroundworker to report progress (via progresschanged event)
2) Set backgroundworker to support task Cancellation
3) defines the handling events for Progress Updates:
Static voidBw_progresschanged (ObjectSender,ProgresschangedeventargsE ){Console. Writeline (String. Format ("{0 }:{ 1} % completed",Datetime. Now. tostring ("Mm: SS"), E. progresspercentage ));}
4) defines the processing events for task completion:
Static voidBw_runworkercompleted (ObjectSender,RunworkercompletedeventargsE ){If(E. cancelled)Console. Writeline ("Cancelled");Else if(E. Error! =Null)Console. Writeline (E. Error. tostring ());ElseConsole. Writeline (E. Result );Console. Writeline (Datetime. Now. tostring ("Mm: SS"));}
5) defines the main method of the task:
Static voidBw_dowork (ObjectSender,DoworkeventargsE) {(E. ArgumentAsAutoresetevent). Waitone ();For(IntI = 0; I <= 100; I + = 10 ){// If (BW. cancellationpending) // {// console. writeline ("cancelling... "); // For (Int J = 0; j <= 100; j + = 20) // {// BW. reportprogress (j); // thread. sleep (500); //} // E. cancel = true; // return ;//}Bw. reportprogress (I );Thread. Sleep (500);} e. Result = 100 ;}
6) Events after dispose backgroundworker are defined:
Static voidBw_disposed (ObjectSender,EventargsE ){Console. Writeline ("Disposed");}
7) Use semaphores as event status parameters to delay task execution by 2 seconds
8) the main thread uses isbusy to determine whether the task is being executed and polling and waiting
9) Finally, the dispose component
ProgramThe execution result is as follows:
You can see:
1) The task is executed in 2 seconds. The task is executed in 10 stages, and the progress is reported in each stage. Each stage takes 500 milliseconds
2) After the task is executed, you can set the value of the result attribute. This value can be obtained in bw_runworkercompleted.
Let's restore the annotated code to see how the task is canceled:
we can see that the task is canceled in 2 seconds. Note that the cancelasync () method cannot actually cancel the task execution, to truly cancel a task, you must constantly check the cancellationpending attribute in the main method of the task. If it is set to true, it indicates that you want to cancel the task and then execute some cancellation tasks, after completion, set the cancel attribute to true and end the task subject. This is because the process of canceling rollback for a long time may also be long, we can also report the progress of canceled behaviors in the subject method. You can perform related experiments on your own and find that in the console program, the dowork progressreport of backgroundworker is based on two independent threads, both of which are based on the thread pool, in winform, The backgroundworker's dowork is executed on the UI thread based on the independent thread in the thread pool.