[ Pobierz całość w formacie PDF ]
.Factory.StartNew(() => {Console.WriteLine("Task 1 waiting for cancellation");tokenSource.Token.WaitHandle.WaitOne();Console.WriteLine("Task 1 cancelled");tokenSource.Token.ThrowIfCancellationRequested();}, tokenSource.Token);// create the second task, which will use a code loopTask t2 = Task.Factory.StartNew(() => {// enter a loop until t1 is cancelledwhile (!t1.Status.HasFlag(TaskStatus.Canceled)) {// do nothing - this is a code loop}Console.WriteLine("Task 2 exited code loop");});// create the third loop which will use spin waitingTask t3 = Task.Factory.StartNew(() => {// enter the spin wait loopwhile (t1.Status != TaskStatus.Canceled) {Thread.SpinWait(1000);}Console.WriteLine("Task 3 exited spin wait loop");});// prompt the user to hit enter to cancelConsole.WriteLine("Press enter to cancel token");Console.ReadLine();tokenSource.Cancel();// wait for input before exitingConsole.WriteLine("Main method complete.Press enter to finish.");Console.ReadLine();}}}SummaryThis chapter introduced you to the basic building blocks that we will use to explore the TaskProgramming Library (TPL).You learned how to create and start Tasks, cancel Tasks as they are running,handle exceptions when things go wrong, and check the status of Tasks all essential to writing parallelprograms.In the next chapter, we ll look at one of the most common complexities that parallelprogrammers face, specifically sharing data between tasks.48C H A P T E R 3 % % %Sharing DataListing 3-1.Hello Taskusing System;using System.Threading.Tasks;namespace Listing_01 {class BankAccount {public int Balance {get;set;}}class Listing_01 {static void Main(string[] args) {// create the bank account instanceBankAccount account = new BankAccount();// create an array of tasksTask[] tasks = new Task[10];for (int i = 0; i {// enter a loop for 1000 balance updatesfor (int j = 0; j {// create the first child taskTask childTask = new Task(() => {// write out a message and waitConsole.WriteLine("Child 1 running");Thread.Sleep(1000);Console.WriteLine("Child 1 finished");throw new Exception();}, TaskCreationOptions.AttachedToParent);// create an attached continuationchildTask.ContinueWith(antecedent => {// write out a message and waitConsole.WriteLine("Continuation running");Thread.Sleep(1000);Console.WriteLine("Continuation finished");},128CHAPTER 4 % COORDINATING TASKSTaskContinuationOptions.AttachedToParent| TaskContinuationOptions.OnlyOnFaulted);Console.WriteLine("Starting child task.");childTask.Start();});// start the parent taskparentTask.Start();try {// wait for the parent taskConsole.WriteLine("Waiting for parent task");parentTask.Wait();Console.WriteLine("Parent task finished");} catch (AggregateException ex) {Console.WriteLine("Exception: {0}", ex.InnerException.GetType());}// wait for input before exitingConsole.WriteLine("Press enter to finish");Console.ReadLine();}}}The Wait() call on the parent Task will not return until the parent and all of its attached childrenhave finished.You will see that the child Task throws an exception, which is packaged up by the parentTask and thrown again, allowing us to catch it when calling a trigger method on the parent.Theexception will be a nested AggregateException; in other words, the original exception will have beenpackaged into an AggregateException by the child, and that will be packaged again into anotherAggregateException by the parent.The third part of the relationship relates to Task status.When a parentTask has finished executing and is waiting for its attached children to finish, its status will beTaskStatus.WaitingForChildrenToComplete.You can extend the scope of the attached child relationship to Task continuations by using theTaskContinuationOptions.AttachedToParent value as an argument when calling the ContinueWith()method on an attached child Task
[ Pobierz całość w formacie PDF ]