To simplify multi-threaded programming,. NET 4 provides classes in the System. Threading. Tasks namespace to help developers with multi-threaded programming. The Task class is used to represent a thread. The simplest Task class accepts an Action delegate as the method to be executed, and calls the Start method to Start running in another thread. For example:
Using System;
Using System. Threading. Tasks;
Namespace TaskParallel
{
Class Program
{
Static void Main (string [] args)
{
Task task = new Task () => Console. WriteLine ("Write from another thread "));
Task. Start ();
Console. WriteLine ("Main Thread ");
Console. ReadLine ();
}
}
}
The order of the two outputs is not certain, but it is likely that:
Main Thread
Write from another thread
You can also use the Task. Factory. StartNew method. This method constructs a Task and starts running immediately. It is equivalent to connecting the constructor of the Task and the Start method for execution.
The Task class also has a constructor that can accept the Action <object> delegate and pass parameters to the Action:
Static void Main (string [] args)
{
For (int I = 0; I <5; I ++)
{
Task t = new Task (obj => Console. WriteLine ("Thread No" + obj), I );
T. Start ();
}
Console. ReadLine ();
}
The output result is similar:
Thread No 2
Thread No 1
Thread No 3
Thread No 0
Thread No 4
You can use the Task <T> class to obtain the returned value. T is the type of the returned value. For example:
Static void Main (string [] args)
{
Task <int> t = new Task <int> () =>
{
Int s = 0;
For (int I = 0; I <10000; I ++)
S + = I;
Return s;
});
T. Start ();
Console. WriteLine ("I'm computing ");
Console. WriteLine (t. Result );
Console. ReadLine ();
}
Result:
I'm computing
49995000
When you access t. Result,. net will ensure that the Task code has been executed and the Result has been obtained. Otherwise, the thread will block until the Result calculation is complete.
The Task library provides a method to actively terminate a thread. First, create a CancellationTokenSource, pass its Token attribute through the Task constructor, and round-robin The IsCancellationReqeusted attribute of the token within the Task, if true is detected, the thread is terminated. Call the Cancel Method of tokenSource in the parent thread to terminate the thread. Note: This is the method that the thread takes the initiative to terminate itself. The code in the Task must be terminated by itself, and. NET will not forcibly terminate the task thread, even if the parent thread calls the Cancel Method of tokenSource.
For example, if the following code does not have a break statement in the else statement block, the subthread will not terminate.
Using System;
Using System. Threading;
Using System. Threading. Tasks;
Namespace TaskParallel
{
Class Program
{
Static void Main (string [] args)
{
CancellationTokenSource tks = new CancellationTokenSource ();
CancellationToken token = tks. Token;
Long I = 0;
Task task = new Task () =>
{
While (true)
{
If (! Token. IsCancellationRequested)
I ++;
Else
{
Console. WriteLine ("Task is canceled, it looped" + I + "times ");
Break;
}
}
}, Token );
Task. Start ();
Console. WriteLine ("Press Enter to Cancel task ");
Console. ReadLine ();
Tks. Cancel ();
Console. ReadLine ();
}
}
}
You can also use the CancellationToken's Register Method to Register a delegate for the token. When the Cancel Method of tokenSource is called, the Delegate will be executed. This delegate is executed in the thread that calls the Cancel method.
Token. Register () =>{ Console. WriteLine ("Delegate Invoked ");});
To suspend the current thread and Wait for a thread to complete its execution, you can use the Wait () method of the execution thread. The Wait method has some overload methods that can specify the waiting time. For example:
Static void Main (string [] args)
{
Task t1 = new Task () =>
{
Console. WriteLine ("Task 1 Starts ...");
Thread. Sleep (3000 );
Console. WriteLine ("Task1 Ends ");
});
T1.Start ();
Task t2 = new Task () =>
{
Console. WriteLine ("Task2 Starts ...");
T1.Wait ();
Console. WriteLine ("Task2 Ends ");
});
Task t3 = new Task () =>
{
Console. WriteLine ("Task 3 is waiting Task1 for 1 second ...");
Bool finished = t1.Wait (1000 );
If (finished)
Console. WriteLine ("T1 is finished ");
Else
Console. WriteLine ("T1 is not finished ");
});
T2.Start ();
T3.Start ();
Console. ReadLine ();
}
The execution result is:
Task 1 Starts...
Task2 Starts...
Task 3 is waiting Task1 for 1 second...
T1 is not finished
Task1 Ends
Task2 Ends
You can use the Task. WaitAll method after multiple threads are executed,
Task t4 = new Task () =>
{
Console. WriteLine ("Waiting for all ");
Task. WaitAll (t1, t2, t3 );
Console. WriteLine ("Task4 Ends ");
});
T4.Start ();
There is also a Task. WaitAny, which can wait for any method in a group of threads to finish execution. The usage is similar.
The following describes how to handle exceptions in a Task. Generally, exceptions in a thread delegate will lead to thread termination, but exceptions will not be thrown. For example:
Task t = new Task () =>
{
Throw new Exception ();
Console. WriteLine ("Thread Ends ");
});
T. Start ();
Console. WriteLine ("Main Ends ");
The output is:
Main Ends
When Wait, WaitAll, WaitAny, Task. Result is called, AggerateException is thrown. In AggerateExcepiton, exceptions thrown by all threads can be handled:
Static void Main (string [] args)
{
Task t1 = new Task () =>
{
Throw new Exception ();
Console. WriteLine ("T1 Ends ");
});
Task t2 = new Task () =>
{
Throw new ArgumentException ();
Console. WriteLine ("T2 Ends ");
});
T1.Start ();
T2.Start ();
Try
{
Task. WaitAll (t1, t2 );
}
Catch (aggresponexception ex)
{
Foreach (var inner in ex. InnerExceptions)
{
Console. WriteLine (inner. GetType () + "" + inner. Source );
}
}
Console. WriteLine ("Main Ends ");
}
}
Sometimes some exceptions need to be treated differently. Some exceptions need to be thrown again. aggresponexception provides a Handle method to receive a Func <Exception, bool> delegate as a parameter, if you do not need to throw it again, true is returned; otherwise, false is returned.
Try
{
Task. WaitAll (t1, t2 );
}
Catch (aggresponexception ex)
{
Foreach (var inner in ex. InnerExceptions)
{
Console. WriteLine (inner. GetType () + "" + inner. Source );
}
Ex. Handle (e) =>
{
If (e is ArgumentException)
{
Console. WriteLine ("Argument Exception is captured ");
Return true;
}
Else
Return false;
});
}
In this way, unhandled exceptions will be thrown and aggresponexception will be thrown.
Author: yinzixin