Free mag vol1 | Page 791

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