|
What is Async COM? Author: Richard Grimes Windows 2000 now comes with asynchronous COM, or to give it its more accurate name non-blocking calls. It was introduced to solve the problem of client and RPC threads blocking while a COM call is active. The problem is this: COM is synchronous, so it means that when a client makes a method request the client thread is blocked until the server has handled that request. This means that, for example, if the client thread is a UI thread it could affect how often a window updates, giving a nasty jerky effect. On the server side things are a little better, but still has problems. The server can use a multi threaded apartment to allow RPC to maintain a pool of threads (at 'normal' priority) to accept COM requests. However, it is those actual threads that are used to execute the object method, so it means that when an RPC thread is executing a COM request it is not available to accept another call. Furthermore, if RPC determines that the server is under stress it will create extra threads to handle the requests, this gives extra 'availability' because each of the client requests will be accepted, but degrades performance because more threads require more work by the processors in your system. For this reason RPC will make sure that once the time of stress is over it will kill the extra threads to keep the pool to a manageable size. However, RPC does not allow you to specify a minimum or maximum number of threads that it will use, nor the priority of those threads. Non-blocking calls on the server-side allows the developer to implement a thread pool specifically to execute the async methods freeing the RPC threads with the task of merely accepting the method calls and then placing them in a work queue. Since you have the responsibility of implementing the thread pool it means that you can decide the number of threads in the pool and the priority of those threads. If you don't want this extra work, you can use QueueUserWorkItem() to use a system provided thread pool (however, in this case you do not have any control over the priority of the threads, nor how many threads are created). The great thing about both server-side and client-side non-blocking calls is that the same calls are made 'on the wire' whether blocking or non-blocking calls are made. Also, the client does not care if the server implements non-blocking calls and the server does not care if it is called using a non-blocking call. All of the 'magic' is performed by the proxy-stub files, which means that the interface cannot be type library marshalled. To use non-blocking calls the interface must be described in IDL using async_iid() attribute. This basically tells MIDL that it should generate proxy-stub code for the interface when it is called synchronously and asynchronously. The proxy object itself will be called for just the synchronous call. To call the object asynchronously the client must query the proxy for the ICallFactory interface and call CreateCall(). This instructs the proxy to create a separate object called a call object, which implements the proxy non-blocking interface. The asynchronous interface has two methods for every method that is on the synchronous interface: for each there is a Begin_ method and a Finish_ method. The Begin_ method has parameters for all of the [in] and [in, out] parameters on the synchronous method and the Finish_ method has parameters for all of the [in, out] and [out] parameters, and of course, the return value of Finish_ is the actual return value of the method. So for example, if you have a method like this on the synchronous interface:
HRESULT GetStudent([in] UINT uStudentID, [out] IStudent** ppStudent);
the asynchronous interface will have these two methods:
HRESULT Begin_GetStudent([in] UINT uStudentID);
HRESULT Finish_GetStudent([out] IStudent** ppStudent);
When the client calls the Begin_ method it instructs the call object to make the call, however, the Begin_ method will return immediately and hence the HRESULT it returns will have no bearing on whether the method was successfully made. When the actual method has completed, the call object will be informed of the result of the call (all the [out] parameters and the HRESULT) which the client can obtain by calling the Finish_ method. If the client calls Finish_ before the method has completed the client thread will block, so it is best to perform some other processing before calling the Finish_ method. The call object also implements ISynchronize that the client can call to poll to see if the method has completed, and the client can also provide its own implementation of this interface to provide a Win32 synchronization object which the call object will signal on method completion and the client thread can wait on this object using the normal Win32 wait methods. Further, the call object implements ICancelMethodCalls which has methods that can be called to cancel a pending method. On the server-side, the component should implement ICallFactory to handle non-blocking calls. COM will query for this interface to see if the component can be called asynchronously. It will call the interface to create a call object specific to the component which COM will aggregate into a synchronization object that COM maintains to manage the return call back to the client. Your code must implement the call object and hence the asynchronous version of the interface. When this call object is called to perform a non-blocking call, an RPC thread will be used to call the Begin_ method. Your code should implement this by queuing the request into some thread pool that you have implemented and then return immediately. This will free the RPC thread to take another call. As I mentioned earlier, you have to implement a thread pool and your thread function should use the synchronization object created by COM to indicate that it has finished its work. This prompts the system to call the Finish_ method to get the return values from the call and return them back to the client. As a post script, you cannot use asynchronous calls on COM+ configured components, COM+ will refuse to call your object for a call object. However, this is not such a great problem because a configured component can call an unconfigured component asynchronously. What do you think of this article? You can also write a review. We will publish the best ones here on this article. Send your review to [email protected]. Mail a question to the author!! As part of the IDevResource commitment to Open Publishing, all of our authors are available to answer all of your trickiest questions at Author Central. For information about the authors, or to mail a question, visit them at Author Central. Want to read more articles by this author? Try these: Byte size articles: ATL Server By Richard Grimes, 220200 COM and Apartments By Richard Grimes, January 7th 2000 An Introduction to WTL By Richard Grimes, January 7th 2000 An Introduction to Interface Programming By Richard Grimes, January 7th 2000 Full size articles: What is Async COM? By Richard Grimes. Microsoft Transaction Server By Richard Grimes, December 9th 1999 What COM is all about By Richard Grimes, December 6th 1999 More COM Library articles: CAtlBitmapButton - ATL/WTL Ownerdraw Superclassed Bitmap Button By Amit Dey. ATL COM and ADO By Paddy Srinivas. ATL COM and ADO By Amit Dey. COM Singletons: A Dangerous Animal By Richard Blewett. ASP COM Objects By Jan Verhoeven. SafeArrays - For the Beginner By A. Abdul Azeez. COM+ Basics - Creating your first COM+ Application By Martin Lapierre. COM+ - the backbone of Windows DNA By Mahesh Bhide. Exploring COM Threading and Apartments By Anthony Toivonen. COM on Linux By Frank Rem. ATL Server By Richard Grimes. ATL Internals - Part 2 By Shivesh Viswanathan. How to use DDX with WTL By Girish Bharadwaj. COM Patterns By Tony Toivonen. COM+ Object Pooling By Jeremiah Talkar. What are COM Pipes? By Richard Grimes. Java COM Integration - Use Visual J++ to implement COM Objects By Gopalan Suresh Raj. Developing an MSMQ Server Application using VJ++ By Gopalan Suresh Raj. Developing an MSMQ Client using VJ++ By Gopalan Suresh Raj. What is Async COM? By Richard Grimes. Coding a DCOM Server Component from IDL By Gopalan Suresh Raj. Coding a DCOM Client By Gopalan Suresh Raj. Threads and Apartments By Brad Wilson. WTL Architecture By Richard Grimes. The MTS Series by Gopalan Suresh Raj: Microsoft Transaction Server By Gopalan Suresh Raj. Developing a Simple MTS Server Component By Gopalan Suresh Raj. Developing a Simple MTS Client Application By Gopalan Suresh Raj. Developing The Bank Account IDL By Gopalan Suresh Raj. MTS Server Component By Gopalan Suresh Raj. MTS Client By Gopalan Suresh Raj. Other Articles Active Template Library: Architecture & Internals By Shivesh Viswanathan. Microsoft Transaction Server By Richard Grimes. What COM is all about By Richard Grimes. String Binding Moniker By Frank Rem. Author: Richard Grimes Richard Grimes started programming aeons ago on 8-bit computers and hasn't looked back since. He has spent an interesting time as a research scientist (the little known "Grimes Effect" is his creation), underpaid time as a computer trainer and done time as a distributed object developer. ATL took hold of Richard while he was part of a team developing a COM-based workflow system and its elegance and simplicity has had a lasting effect on him. Although his is not an obsessively pure COM existence, he finds that an ATL-assisted COM lifestyle gives him more time to enjoy his garden. Go to Richards pages in Author Central. Contribute to IDR: To contribute an article to IDR, a click here.
|
|