Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

COM+, ErrObject, and Co.  : Page 2

Global variables are not true global variables in VB as you might think. Every application-global, module-global, or static variable is stored in TLS, local memory of the thread where the object was created in. COM+ has a default amount of only eight threads per COM+ application and CPU initially. As the author's investigation shows, ErrObject is stored in TLS too. It means we can get that an error originated in one instance will be seen in quite different instance. Moreover, App is also kept in TLS. It means we can get that some properties of App set in one instance will be seen in another one. Moreover, Microsoft has never published the list of internal objects that are stored in TLS. Fancy, where it can lead us to! Are you frightened to death? The author shows that such architecture is not such fatal as it might seem at first sight.


advertisement
First Results
As you can see the first eight forms show Err().Number is zero, App.Title is “Project1” and at last global variable is equal to zero. Now press command button on the ninth form and get the following results: Err().Number is 5, App.Title is ID of the thread and global variable is 1. It means the ninth instance has got to the thread when one of the previous eight forms was created in. As a rule it is the thread of the first form. The investigation of ThreadID of all created instances testifies to the usage of a simple round robin algorithm for assignment of threads by Microsoft.

Refinements
And now let’s begin to consider the refinements. It is so interesting to clear out what system objects exactly are shared between instances of different components and which ones are not.

We will find out right now:



1. Uncomment the commented section of the code in the client EXE application and recompile the application. The uncommented section introduces the instance of the second component doing the same as the first one.

2. Repeat steps 1-6 but name the new project as Project2 and new coclass as Class2.

Now that you have done it launch nine forms as in the previous case. Fire! As you can see ErrObject is being shared among instances of different components because the fifth form already has 5 as Err().Number value. App and global variables are not shared because the fifth form shows their right values.

The bottom line is:

1. ErrObject is shared between instances of components of different types.

2. Global variables and App object are not shared between instances of components which have different types.

Problem Solving...
It seems to be a pity. You can get rid of global and static variables and frankly speaking you should get rid of them (except when the effect is positive for you, such as when caching static values). But how should we get around the problem with intrinsic system objects like ErrObject and App? Should we introduce critical sections or something like that?

Solving problems first of all we should be aware whether the problem really exists. I know a lot of problems that may be solved just by a bit of healthy sleep. Theory will help us, I believe.

…and Theory
Two axioms come here:

1. Only COM DLL can be placed under COM+ so we will consider the questions of synchronization only for in-process components.

2. All in-process components created with VB use apartment-model threading to provide synchronous access to objects in multithreaded environment.

Let’s point to the main enemy of mankind in multithreaded environment at once. So the main enemy is potential reentrancy. The new call to the component may be for the member the thread was already executing - in this case the thread enters the member a second time - or it may be for another member. If the second member does not yield, it will finish processing before the first member. If it changes module-level data or something else without any critical section the first member was using, the result may be unpredictable. For these purposes there was implemented apartment-model threading in COM.

In apartment-model threading, each thread is like an apartment - all objects created on the thread execute only in this apartment, and are unaware of objects living in other apartments. So let’s consider an apartment just as a thread with some additional metainformation.

In the apartment model, reentrancy is handled in the following way:

1. An apartment’s thread of execution enters an object’s code, because a property or method has been invoked.

2. While the thread is in the property or method, another thread invokes a property or method of the object, and COM serializes this request. (It just places the request as next event to the standard window message queue. Each apartment has window message pumping loop handling all incoming events.) That is, it queues the request until the thread that owns the object’s apartment finishes the member it is currently executing.

3. Before the thread reaches the end of the member, it executes code that yields control of the processor.

4. COM tells the thread to begin executing the serialized request, so that the thread reenters the object’s code.

By serializing method calls for each apartment, COM protects you from reentrancy - unless your code yields control of the processor. Ways in which your code can yield control of the processor may be for instance such as: raising an event that is handled by an object on another thread, or in another process.

VB implementation of apartment-model threading eliminates conflicts in accessing global data from multiple threads by giving each apartment its own copy of global data. A separate copy of all global data such as variables in modules and static variables is maintained for each apartment. In addition to maintaining a separate copy of global data, a Sub Main procedure is executed for each new apartment (that is, for each new thread). Otherwise, there would be no way to initialize global data for the new thread. The first time a client thread requests an object provided by your VB COM DLL, a new apartment is created, and Sub Main executes for that apartment.

In-process components created with VB can be single-threaded or multithreaded. A single-threaded component has only one apartment, which contains all the objects the component provides. The client thread that handles all the calls to objects in the single-threaded in-process component will be the first thread that called CoInitializeEx function. This means that a single-threaded DLL created with Visual Basic is safe to use with a multithreaded client. However, there is a performance trade-off for this safety. Calls from all client threads except one are marshaled, just as if they were out-of-process calls.

A multithreaded component can have as many apartments as there are threads of the client that create instances of the component. Multithreaded COM DLL component provides the following benefits:

1. All of the objects a client creates on a given thread will be created in the same apartment in the DLL. Calls to these objects do not require cross-thread marshaling, making them more efficient.

2. Because an object is only accessed on the thread where it was created, calls are serialized so that a call is never interrupted by a call from another thread.

3. Arguments for cross-thread calls are marshaled, and the calling thread is blocked. This synchronization of data protects the calling thread’s state.

Dllhost.exe acts as a multithreaded host for COM+ components placed in application with Server Activation type. In case it has Library Activation type your client application directly acts as a host for COM+ components.

…and How the Theory Has Helped Us
As you can see apartment-model threading gets around the reentrancy problem.

1. Therefore you cannot see the ErrObject set in the first component from another component until the first component returns control to the caller. Hence just begin any method with On Error GoTo Hell statement and you will never see another’s error. Also propagate an error up to call stack of components and hope for our friends from Redmond.

2. The same thing is about App. Do you often use App properties in your COM+ applications to pass parameters between components? Sounds funny, does not it?

Conclusion
I have just shown a couple of interesting and unexpected things that I had seen behind simple and scanty line “Do not use global variables in VB components under COM+”.

Special thanks to Tanya Rusakova for her Queen English (my native language is C++) and to Jimmy Nilsson for his infinite patience and kindness. The converse is also true.



Victor Novik works with company Scala (http://www.scala.net/) in its RnD centre. He has been working with C++ system and network development for some years and recently he has specialized in COM+ and MS SQL Server development. Also he knows the buzzword XML (it is size of t-shirts, right?) He is a graduate of Moscow State University named after Bauman. Feel free to reach Victor by e-mail at . Your feedback is much appreciated.
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap
Thanks for your registration, follow us on our social networks to keep up-to-date