Tải bản đầy đủ - 0 (trang)
15-7. Handle Exceptions in Tasks

15-7. Handle Exceptions in Tasks

Tải bản đầy đủ - 0trang

CHAPTER 15 ■ PARALLEL PROGRAMMING



Solution

Call the Task.Wait or Task.WaitAll methods within a try...catch block to catch the

System.AggregateException exception. Call the Handle method of AggregateException with a function

delegate—the delegate will receive each exception that has been thrown by the Tasks. Your function

should return true if the exception can be handled, and false otherwise.



How It Works

Catching AggregateException as it is thrown from Task.Wait or Task.WaitAll allows you to be notified of

exceptions that are unhandled by your Task. If an error has occurred, then you will catch a single

instance of System.AggregateException representing all of the exceptions that have been thrown.

You process each individual exception by calling the AggregateException.Handle method, which

accepts a function delegate (usually specified using a lambda expression)—the delegate will be called

once for each exception that has been thrown by your task or tasks. Bear in mind that several threads

may have encountered the same problem, and that you are likely to have to process the same exception

type more than once. If you can handle the exception, your function delegate should return true—

returning false will cause your application to terminate.



■ Tip If you do not catch exceptions from Wait or WaitAll, then any exception thrown by a Task will be

considered unhandled and terminate your application.



The Code

The following example demonstrates how use the AggregateException.Handle method to implement a

custom exception handler function:

using

using

using

using

using

using



System;

System.Collections.Generic;

System.Linq;

System.Text;

System.Threading;

System.Threading.Tasks;



namespace Recipe15_07

{

class Recipe15_07

{

static void Main(string[] args)

{

// Create two tasks, one with a null param.

Task goodTask = Task.Factory.StartNew(() => performTask("good"));

Task badTask = Task.Factory.StartNew(() => performTask("bad"));



742



www.it-ebooks.info



CHAPTER 15 ■ PARALLEL PROGRAMMING



try

{

Task.WaitAll(goodTask, badTask);

}

catch (AggregateException aggex)

{

aggex.Handle(ex => handleException(ex));

}

// Wait to continue.

Console.WriteLine("\nMain method complete. Press Enter");

Console.ReadLine();

}

static bool handleException(Exception exception)

{

Console.WriteLine("Processed Exception");

Console.WriteLine(exception);

// Return true to indicate we have handled the exception.

return true;

}

static void performTask(string label)

{

if (label == "bad")

{

Console.WriteLine("About to throw exception.");

throw new ArgumentOutOfRangeException("label");

}

else

{

Console.WriteLine("performTask for label: {0}", label);

}

}

}

}



15-8. Cancel a Task

Problem

You need to cancel a Task while it is running.



Solution

Create an instance of System.Threading.CancellationTokenSource and call the Token property to obtain a

System.Threading.CancellationToken. Pass a function delegate that calls the Cancel method of your Task



743



www.it-ebooks.info



CHAPTER 15 ■ PARALLEL PROGRAMMING



to the Register method of CancellationToken. Cancel your Task by calling the Cancel method of

CancellationTokenSource.



How It Works

The System.Threading.CancellationTokenSource class provides a mechanism to cancel one or more

tasks. CancellationTokenSource is a factory for System.Threading.CancellationToken.

CancallationToken has the property IsCancellationRequested, which returns true when the Cancel

method is called on the CancellationTokenSource that produced the token. You can also use the

Register method to specify one or more functions to be called when the Cancel method is called. The

sequence for handling cancellation is as follows:

1.



Create an instance of CancellationTokenSource.



2.



Create one or more Tasks to handle your work, passing CancellationToken as a

constructor parameter.



3.



For each Task you have created, obtain a CancellationToken by calling Token

on the CancellationTokenSource created in step 1.



4.



Check the IsCancellationRequested property of the token in your Task body—

if the property returns true, then release any resources and throw an instance

of OperationCanceledException.



5.



When you are ready to cancel, call the Cancel method on the

CancellationTokenSource from step 1.



Note that you must throw an instance of OperationCanceledException to acknowledge the task

cancellation request.



The Code

The following example creates a CancellationToken that is used to create an instance of Task. A method

to be called when the CancellationTokenSource is canceled is registered with the Register method.

When CancellationTokenSource.Cancel is called, the Task is stopped and a message is written to the

console.

using System;

using System.Threading;

using System.Threading.Tasks;

namespace Recipe15_08

{

class Recipe15_08

{

static void Main(string[] args)

{

// Create the token source.

CancellationTokenSource tokenSource = new CancellationTokenSource();

// create the cancellation token

CancellationToken token = tokenSource.Token;



744



www.it-ebooks.info



CHAPTER 15 ■ PARALLEL PROGRAMMING



// Create the task.

Task task = Task.Factory.StartNew(() => printNumbers(token), token);

// register the task with the token

token.Register(() => notifyTaskCanceled ());

// Wait for the user to request cancellation.

Console.WriteLine("Press enter to cancel token");

Console.ReadLine();

// Canceling.

tokenSource.Cancel();

}

static void notifyTaskCanceled()

{

Console.WriteLine("Task cancellation requested");

}

static void printNumbers(CancellationToken token)

{

int i = 0;

while (!token.IsCancellationRequested)

{

Console.WriteLine("Number {0}", i++);

Thread.Sleep(500);

}

throw new OperationCanceledException(token);

}

}

}



15-9. Share Data Between Tasks

Problem

You need to share data safely between Tasks.



Solution

Use the collection classes in the System.Collections.Concurrent namespace.



How It Works

One of the biggest problems when writing parallel or threaded code is ensuring that data is shared safely.

Microsoft has introduced new classes in .NET 4.0 that are designed to be more efficient than using

synchronization around the default collection classes, which we demonstrated in Chapter 4. The



745



www.it-ebooks.info



CHAPTER 15 ■ PARALLEL PROGRAMMING



techniques demonstrated in Chapter 4 will work with the .NET parallel programming model, but the

new collection classes may be more efficient for large-scale applications. Table 15-1 lists the most useful

classes from the System.Collections.Concurrent namespace.

Table 15-1. Useful System.Collections.Concurrent Classes



Class



Description



ConcurrentBag



A thread-safe collection of objects where no typing or ordering is assumed



ConcurrentDictionary



A key/value pair collection



ConcurrentQueue



A first in, first out (FIFO) queue



ConcurrentStack



A last in, first out (LIFO) stack



These new collections take care of managing data automatically—you do not have to use

synchronization techniques in your code.



The Code

The following example creates a ConcurrentStack, which is then used by three Tasks.

using

using

using

using

using

using

using



System;

System.Collections.Generic;

System.Linq;

System.Text;

System.Threading;

System.Threading.Tasks;

System.Collections.Concurrent;



namespace Recipe15_9

{

class Recipe15_9

{

static void Main(string[] args)

{

// Create a concurrent collection.

ConcurrentStack cStack = new ConcurrentStack();

// create tasks that will use the stack

Task task1 = Task.Factory.StartNew(

() => addNumbersToCollection(cStack));

Task task2 = Task.Factory.StartNew(

() => addNumbersToCollection(cStack));

Task task3 = Task.Factory.StartNew(

() => addNumbersToCollection(cStack));



746



www.it-ebooks.info



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

15-7. Handle Exceptions in Tasks

Tải bản đầy đủ ngay(0 tr)

×