CHAPTER 19 MULTITHREADED, PARALLEL, AND ASYNC PROGRAMMING
// Eek! This will not work anymore!
//this.Text = string.Format("Processing {0} on thread {1}", filename,
// Thread.CurrentThread.ManagedThreadId);
// Invoke on the Form object, to allow secondary threads to access controls
// in a thread-safe manner.
this.Invoke((Action)delegate
{
this.Text = string.Format("Processing {0} on thread {1}", filename,
Thread.CurrentThread.ManagedThreadId);
}
);
}
Note The this.Invoke() method is unique to the Windows Forms API. When you are building a WPF
application, you would write this.Dispatcher.Invoke() for the same purpose.
Now, if you run program, the TPL will indeed distribute the workload to multiple threads from the
thread pool, using as many CPUs as possible. However, you will not see the window’s caption display the
name of each unique thread and you won’t see anything if you type in the text box, until all the images
have been processed! The reason is that the primary UI thread is still blocked, waiting for all of the other
threads to finish up their business.
The Task Class
The Task class allows you to easily invoke a method on a secondary thread, and can be used as a simple
alternative to working with asynchronous delegates. Update the Click handler of your Button control as
so:
private void btnProcessImages_Click(object sender, EventArgs e)
{
// Start a new "task" to process the files.
Task.Factory.StartNew(() =>
{
ProcessFiles();
});
}
The Factory property of Task returns a TaskFactory object. When you call its StartNew() method,
you pass in an Action delegate (here, hidden away with a fitting lambda expression) that points to the
method to invoke in an asynchronous manner. With this small update, you will now find that the
window’s title will show which thread from the thread pool is processing a given file, and better yet, the
text area is able to receive input, as the UI thread is no longer blocked.
Handling Cancellation Request
One improvement you can make to the current example is to provide a way for the user to stop the
processing of the image data, via a second (aptly named) Cancel button. Thankfully, the Parallel.For()
736