Asynchronous Programming
Asynchronous Programming
Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places, and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express
Contents Overview Lesson: The .NET Asynchronous Programming Model Lesson: The Asynchronous Programming Model Design Pattern Lesson: How to Make Asynchronous Calls to Any Method Lesson: Protecting State and Data in a Multithreaded Environment Review Lab 7.1: Making Asynchronous Calls to an XML Web Service 1 2 7 19 27 34 36
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2002 Microsoft Corporation. All rights reserved. Microsoft, MS-DOS, Windows, Windows NT, Active X, Authenticode, FrontPage, IntelliSense, MSDN, PowerPoint, Visual Basic, Visual C#, Visual Studio, Win32, and Windows Media are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.
Instructor Notes
Presentation: 90 minutes Lab: 45 minutes In this module, students learn how to use the techniques of asynchronous programming and multithreading to avoid blocking the user interface of an application. After completing this module, students will be able to:
Describe the Microsoft .NET Framework asynchronous programming model. Modify a client application to use built-in .NET Framework support for asynchronous calls to methods. Describe how to add explicit support for asynchronous calls to any method.
To teach this module, you need the Microsoft PowerPoint file 2555A_07.ppt. To prepare for this module:
Read all of the materials for this module. Review the animation for this module. Complete the demonstrations, practice, and lab.
If students are interested in referencing code examples in other languages, point them to Language Equivalents in Microsoft Visual Studio .NET Help documentation. This section provides examples in languages such as Microsoft Visual Basic .NET, C#, and Java. The lab at the end of this module is based on the Expense Report application in Course 2555A, Developing Microsoft .NET Applications for Windows (Visual C# .NET), and is intended to simulate a real-world environment in which students will demonstrate what they learned during the lecture and practice portions of the module. The lab does not provide step-by-step detailed instructions; instead, the students are given tasks to complete in the left column and a list of resources that they can use (if they need help) in the right column. Students get hands-on experience that they need by completing the practice activity in the module.
iii
Overview
Introduction A well-designed Microsoft .NET Framework Windows Forms application includes techniques to prevent blocking user interaction. In this module, you will learn how to use the techniques of asynchronous programming and multithreading to avoid blocking the user interface of an application. Objectives After completing this module, you will be able to:
Describe the .NET Framework asynchronous programming model. Modify a client application to use built-in .NET Framework support for asynchronous calls to methods. Describe how to add explicit support for asynchronous calls to any method.
Define asynchronous programming. List typical scenarios in which asynchronous programming is useful. Describe the .NET asynchronous programming model.
Definition
In a non-programming scenario, consider a painting crew that is painting the rooms in a house that is some distance from town. As they are painting walls of the rooms, the crew chief realizes that they did not bring enough trim paint for the woodwork. The crew chief can tell one of the crew members to go to the paint store to order and wait for more trim paint to be custom mixed to the appropriate color, while the rest of the crew continues to paint the walls. When the crew member finally returns with the trim paint, some members of the crew can switch to painting the woodwork in those rooms where the walls have dried. There are quite a few scenarios in the programming world that involve potential wait times: requests for file or network input/output (I/O), Web access, and so forth. You can use asynchronous techniques in your applications in these scenarios to allow users to remain productive.
.3 Notice that the application is responsive while the XML Web service is being called. You can test this by moving the splitter control in the expense report list window, or by minimizing the main application window. .4 After data is loaded in the expense report list window, close the application.
Lesson objectives
Describe the asynchronous programming model design pattern. List the four ways to be notified of completion and describe appropriate scenarios for each way. List the steps for using asynchronous callback as the notification method.
Modify a client application to use built-in .NET Framework support for asynchronous calls to methods.
Wait on a handle
With the wait on a handle technique, you can specify a maximum time-out to wait for an asynchronous operation to complete. You can also use the System.Threading.WaitHandle.WaitAll method to wait on multiple asynchronous operations and be notified when they have all completed. For more information about using the polling and wait on a handle techniques, see Module 14, Threading and Asynchronous Programming in Course 2349B, Programming with the Microsoft .NET Framework (Microsoft Visual C# .NET).
Definition
asynchronous operation completes, in this case the AsyncCB method of the form from which you make the call.
AsyncCallback delCB = new AsyncCallback( this.AsyncCB);
Notice that part of the .NET Framework support provided for asynchronous programming is the AsyncCallback delegate class. The signature for a method referred to by an AsyncCallback delegate is as follows.
void AsyncCB (IAsyncResult ar);
For more information about the AsyncCallback delegate, search for AsyncCallback delegate in the Microsoft Visual Studio .NET Help documentation. .2 Initiate the asynchronous call by invoking the BeginOperation method, in this case WS.BeginGetReportsForEmployee, and passing it the callback delegate, in this case, delCB. Notice that the callback delegate is always passed in as the next to the last parameter.
WS.BeginGetReportsForEmployee( username, pwdToken, RecordCursor, 10, TotalNumRecords, delCB, null);
The final parameter of the BeginInvoke method is of type System.Object and is for user data. This user data is passed into the callback when the operation is completed in the AsyncState property of the IAsyncResult parameter of the callback. The .NET Framework will take care of allocating a thread from the thread pool to run the code in the GetReportsForEmployee method and, when it completes, will call the method pointed to by delCB (AsyncCB).
Exceptions
If the asynchronous operation throws an exception, it will be returned from the call to the EndOperation method.
The .NET Framework provides a MethodInvoker delegate class that you can use to call generic methods. In the previous code sample, you create a delegate that refers to the UpdateUI method in the current object. The signature for a method referred to by a MethodInvoker delegate is as follows.
void UpdateUI();
This call to the forms BeginInvoke method will cause the method referred to by mi to be called on the main thread and therefore update the user interface (UI) safely. By calling the BeginInvoke method instead of the Invoke method, the worker thread used to make the asynchronous call returns to the thread pool faster, thus avoiding exhaustion of threads in the thread pool.
A Microsoft Windows Forms client application calls an XML Web service to retrieve and change information about expense reports. The XML Web service provides a SubmitReport method that takes an expense report, validates it, and adds it to the database of expense reports. When a Web service reference is added to a Microsoft Visual Studio .NET project, a client proxy class for the XML Web service is generated. In addition to the synchronous SubmitReport method, the proxy includes the asynchronous BeginSubmitReport and EndSubmitReport methods. A callback method named SubmitReportCallback is used as the callback method for the asynchronous operation. The asynchronous operation is started by calling the proxys BeignSubmitReport method, passing a delegate object that refers to the callback method. When the BeginSubmitReport method is called, it calls the SubmitReport method on another thread from the runtimes thread pool and returns immediately to the caller. The client is free to continue executing other code and the user interface remains responsive. When the SubmitReport method completes, the callback method is invoked. The callback method invokes the EndSubmitReport method to retrieve the results of the XML Web service call. If the SubmitReport method completed successfully, the EndSubmitReport method returns the results; otherwise, an exception is thrown in the EndSubmitReport method for the callback to handle. The application displays the results of the XML Web service call by using the UpdateUI method. The UpdateUI method manipulates controls to show the results. Controls can only be called safely from the applications main thread. The callback method is not executing on the applications main thread, and therefore cannot call the UpdateUI method directly. Instead, it calls the forms thread-safe BeginInvoke method, passing it a delegate to the UpdateUI method. BeginInvoke then executes this method on the main thread.
.3 Find the next TODO comment. Add the code to begin the call to the XML Web service.
WS.BeginGetReportsForEmployee(null, null, 0, 10, TotalReports, asyncCB, null);
.4 Find the next TODO comment and uncomment the line of code below the TODO comment. .5 Find the next two TODO comments. Comment out the rest of the code (the synchronous code) in the method. .6 Find the next TODO comment. Add the code to finish the call to the XML Web service.
ExpenseReports = WS.EndGetReportsForEmployee(result, out TotalReports);
.7 Find the next TODO comment. Add the code to instantiate a MethodInvoker delegate that points to the UpdateUI method of this class.
MethodInvoker mi = new MethodInvoker(this.UpdateUI);
.8 Find the next TODO comment. Add the code to call BeginInvoke on this form, passing the MethodInvoker delegate created in step 6.
this.BeginInvoke(mi);
Introduction
It is not necessary for a called object to provide explicit support for asynchronous calls. The .NET Framework provides services required for you to call any method asynchronously. After completing this lesson, you will be able to:
Lesson objectives
Describe how to make asynchronous calls to any method. Explicitly create and call asynchronous delegates.
11
The previous code declares a delegate to a method that returns an integer and takes two integers as parameters. Because Microsoft Visual C# and Microsoft Visual Basic .NET compilers support asynchronous delegates, they generate the Invoke method and the BeginInvoke and EndInvoke methods when you declare the delegate. Use the Invoke method if you want to call the target method synchronously. Use the BeginInvoke method to call the target method asynchronously. The runtime queues the request and returns immediately to the caller. The target method will be called on a thread from the thread pool. The original thread that submitted the request is free to continue executing in parallel to the target method, which is running on a thread pool thread. If a callback has been specified on BeginInvoke, it is called when the target method returns. In the callback, the EndInvoke method is used to obtain the return value and the in/out parameters. If the callback is not specified on BeginInvoke, you can use the other asynchronous design pattern techniques, for example, polling, on the original thread that submitted a request. Procedure: Instantiating the delegate Instantiate the class that contains the method that the delegate will point to.
TotalReturnCalc tr = new TotalReturnCalc();
In the code example above, this refers to the object from which you are making the asynchronous call. Alternatively, the method that handles the callback could be in a different object, if necessary for your scenario. Procedure: Calling the BeginInvokemet hod To call the BeginInvoke method, pass the callback delegate, named cb in the code example, to the BeginInvoke method as the second to last parameter.
The final parameter of the BeginInvoke method is of type System.Object and is for user data. This user data is passed into the callback when the operation is completed in the AsyncState property of the IAsyncResult parameter of the callback.
If the asynchronous operation throws an exception, it will be returned from the call to the EndInvoke method. In Windows Forms applications, you must return control to the main thread before updating the user interface.
this.BeginInvoke(mi);
By calling the UpdateUI method asynchronously, by using BeginInvoke instead of Invoke, the worker thread used to make the asynchronous call returns to the thread pool faster, thus promoting better application performance. Notice that this step is necessary only if the UI in a Windows Forms application must be updated. Also notice that all of the steps after creating the delegate are the same in this case as they are in the case in which a delegate is not used.
13
Lesson objective
Introduction
For many Windows Forms applications, little state protection code may be necessary, because most access of object state happens on the main thread. However, this will not be the case for every application. The System.Threading namespace provides classes and interfaces for synchronizing access to data to provide thread safety. You can use the SynchronizationAttribute on any class that is derived from ContextBoundObject to synchronize all instance methods and fields. All objects in the same context domain share the same lock. Multiple threads are allowed to access the instance methods and fields, but only a single thread is allowed at any one time. Static members are not protected from concurrent access by multiple threads. Note Using automatic synchronization can incur more overhead than using manual synchronization techniques.
Automatic synchronization
Another technique that you can use is a compiler keyword to synchronize blocks of code, instance methods, and static methods. In Visual C#, the keyword is lock. This keyword uses the Monitor class to lock the object. When you use the lock keyword, the compiler generates code. The Visual C# compiler emits a try/finally block with Monitor.Enter at the beginning of the try, and Monitor.Exit in the finally block. If an exception is thrown inside of the lock block, the finally handler runs to allow you to perform any clean-up work. The C# statement, of the form lock(x) where x is an expression of a referencetype, is equivalent to the following except that x is evaluated only once:
System.Threading.Monitor.Enter(x); try { ... } finally { System.Threading.Monitor.Exit(x); }
The lock keyword marks a statement block as a critical section. lock(expression) statement_block, where expression specifies the object that you want to lock on. expression must be a reference type. Typically, expression is this if you want to protect an instance variable, or typeof(class) if you want to protect a static variable or if the critical section occurs in a static method in the specified class. The statement_block includes the statements of the critical section. For example, to synchronize access in a static method:
15
Manual synchronization
You can use the Monitor, Interlocked, Mutex, ManualResetEvent, AutoResetEvent, and ReaderWriterLock classes to acquire and release a lock to protect global, static, and instance fields and global, static, and instance methods. For many UI-based applications, little or no special synchronization code is required. All of the changes of the UI must happen on the main application thread, so this usually forces synchronous access to state information. Also, careful enabling and disabling of UI elements can prevent the application from getting into an undefined state. For example, the Expense Reporting sample application enables and disables buttons as asynchronous XML Web service calls are made to prevent threading-related problems. Therefore, no special synchronization code is required in the Expense Reporting application, other than the use of MethodInvoker delegates to switch control to the main thread upon completion of asynchronous calls. For more information about synchronization techniques, see Module 14, Threading and Asynchronous Programming in Course 2349B, Programming with the Microsoft .NET Framework (Microsoft Visual C# .NET).
17
Notice that although Increment was called five times for the unsafe test, the value of the counter never reaches five. Also, the start and stop notifications are interspersed among different threads. In the lock version, the start and stop notifications are paired for each thread, and the counter is correctly incremented to five.
Review
.1 When and why would you use asynchronous programming techniques in an application? You should use asynchronous programming techniques in an application with significant user interaction to avoid blocking the user interface during slow method calls, such as XML Web service calls.
.2 In a Windows Forms application, what are the main steps to follow to use the asynchronous programming design pattern with an asynchronous callback for completion? The main steps are: 1. Create the asynchronous callback delegate. 2. Invoke the BeginOperation method, passing it the callback. 3. Inside the callback, invoke the EndOperation method for completion. 4. Return control to the main thread and update the user interface.
.3 List the four ways to complete an asynchronous call. Four ways to complete the asynchronous call are: Using a callback Polling Calling EndOperation Waiting on a handle
.4 Why do you need to return control to the main thread before updating the UI in Windows Forms applications? You need to return control to the main thread before updating the UI because Windows Forms controls can be safely accessed only from the main thread.
.5 What additional step must you follow to asynchronously call a method of any class? When you want to asynchronously call methods in classes without builtin asynchronous support, you must explicitly create the delegate for the method you want to invoke. After that, follow the same steps required to asynchronously call methods in a class with built-in asynchronous support.
19
.6 If an asynchronous operation throws an exception, when does your code receive the exception? The exception is thrown when the EndOperation method is called.
.7 What keyword is provided by the C# language for controlling access by multiple threads to a block of code? The C# language provides the lock keyword to control access by multiple threads to a block of code.
Make asynchronous calls by using the .NET Framework asynchronous design pattern. Convert synchronous calls to asynchronous calls by using the .NET Framework asynchronous design pattern. Use the Visual Studio .NET debugger to follow the flow of asynchronous calls.
Note This lab focuses on the concepts in Module 7, Asynchronous Programming, in Course 2555A, Developing Microsoft .NET Applications for Windows (Visual C# .NET). As a result, this lab may not comply with Microsoft security recommendations. Prerequisites Before working on this lab, you must have:
The knowledge and skills to develop a simple Windows Forms application by using a Visual Studio .NETcompatible programming language. The knowledge and skills to debug an application by using Visual Studio .NET. The knowledge and skills to call XML Web services and make asynchronous calls by using the .NET Framework asynchronous design pattern.
Scenario
The Expense Report application makes numerous calls to an XML Web service. To improve the responsiveness and usability of the application, all of the XML Web service calls should be made asynchronously. To make the calls asynchronous, you must perform the following tasks:
Write the method that handles the asynchronous callback. Write the method that updates the user interface.
In the starter code for this lab, the asynchronous callback method and user interface update method are already written, and some of the XML Web service calls are already converted. In this lab, you will convert the rest of the synchronous XML Web service calls to asynchronous calls and then use the Visual Studio debugger to follow the flow of the asynchronous calls in the resulting code. Lab Setup There are starter and solution files associated with this lab. Browse to install_folder\Labfiles\Lab07_1\Ex01\Starter to find the starter files, and browse to install_folder\Labfiles\Lab07_1\Ex01\Solution to find the solution files. If you performed a default installation of the course files, install_folder corresponds to C:\Program Files\Msdntrain\2555.
Tasks
1. Open the ExpenseReport project in
Additional information For more information about opening a project file and starting an application, see the following resource:
a.
The Visual Studio .NET Help documentation. For additional information about opening a project file, in Search, select the Search in titles only check box, then search by using the phrase Open Project Dialog Box. For additional information about starting an application in the Designer, in Index, search by using the phrase Debugging Windows Applications.
the code. Refer to the synchronous versions of the calls to see which parameters to pass: The first four parameters should be the same. The fifth parameter should not use the ref keyword in the asynchronous version. The sixth parameter should be the callback delegate. The seventh parameter should be null.
detailed information about the tasks that you must perform to convert the synchronous XML Web service calls in the constructor to asynchronous calls.
b. For more information about how to make
asynchronous calls, see the following resources: Practice: Making an Asynchronous Call to an XML Web Service in Module 7 Asynchronous Programming, in Course 2555A, Developing Microsoft .NET Applications for Windows (Visual C# .NET). Lesson: The Asynchronous Programming Model Design Pattern in Module 7 Asynchronous Programming, in Course
21
2555A, Developing Microsoft .NET Applications for Windows (Visual C# .NET). The .NET Framework SDK documentation. For more information about the asynchronous design pattern, search by using the phrase Including Asynchronous Calls.
Tasks
3. View the flow of asynchronous code by setting
Additional information
a. For more information about debugging and
breakpoints in the ExpenseReportList constructor and the GetReportsCB and UpdateReportsUI methods.
a.
controlling the flow of asynchronous calls, see the following resources: Practice: Making an Asynchronous Call to an XML Web Service in Module 7 Asynchronous Programming, in Course 2555A, Developing Microsoft .NET Applications for Windows (Visual C# .NET). This practice contains information about how to debug an asynchronous call. Lesson: The Asynchronous Programming Model Design Pattern in Module 7 Asynchronous Programming, in Course 2555A, Developing Microsoft .NET Applications for Windows (Visual C# .NET). This lesson contains information about the flow of control of an asynchronous call.
Run the application in the Visual Studio debugger. Click View Submitted Reports. Step through the code, and make sure it executes as expected. Confirm the correct behavior in the user interface by making sure that the expense reports are downloaded asynchronously when a new list window is opened.
b.