An important issue that the developer of MTS applications needs to consider is the threading model that is used by the components of the application. The threading model of a component determines how the methods of the component are assigned to threads in order to be executed. The MTS environment itself manages all of the threads associated with its applications. A component should never create any threads on its own. This is primarily of concern to J++ and C++ developers, who have the ability to create threads directly. Developers creating objects in Visual Basic do not need to worry about this, as there is no way for them to explicitly create a thread.
A thread is simply defined as a single path of code that is being executed. There are four threading models that a component could have. The threading model for a component is determined at the compile time for the component. There is a registry attribute for each component in MTS called ThreadingModel, which indicates what threading model MTS should use for this component. The four threading models are single threaded, apartment-threaded, free-threaded, and both.
If a component is marked as Single Threaded, then all methods of that component will execute on the main thread. There is one main thread for each MTS application. Since there is only one thread, it means that only one method can execute at any given time. If there are multiple single threaded components that are being accessed my multiple clients simultaneously, then it is easy to see why a bottleneck will occur. Since only one method can execute at a time, all of the other methods will be sitting around waiting their turn. This can essentially grind a system to a halt.
A good rule of thumb to remember is Single Threading = BAD!
In a component that is marked as Apartment Threaded, each method of that component will execute on a thread that is associated with that component. Since each component running inside MTS has its own thread, this separates the methods into their own "Apartments", with each instance of a component corresponding to one apartment. While there is only one thread inside of a component, each instance of that component will have its own thread apartment. This will alleviate a great number of the problems that a single threaded component has. Since multiple components can be executing methods in their own apartments simultaneously, the scalability constraints that the single threaded components have are greatly relaxed.
A Free Threaded object is also known as a multi-threaded or multi-threaded apartment object. An application in MTS can have only one multi-thread apartment (MTA) in it. This MTA can have zero or more threads within it. Any objects that are marked as free threaded will be created in the MTA, regardless of where they were created. Now, all of this may sound great. "Wow, multiple threads! Must mean great scalability" This is not necessarily the case. To see the problem, we need to look at how calls are made from cone component to another.
When a call is made from one component to another component within the same the apartment, the call is a direct function call. In the Win32 environment, this is a very fast operation. If a call has to be made from one apartment to another, then a proxy needs to be created in order to make the call. What this does is add overhead to every function call, and slows down the system. Since a free threaded component will ALWAYS be created in the multi-threaded apartment, even if it was created from a single thread apartment, then all calls to access that component will have to be made by a proxy. And with proxy calls being slower than direct calls, the performance of this object will be reduced. This means that even though free-threaded components sound good, they will extract a performance penalty.
There is another type of threading model called Both. This is a special type of threading model in that the object has the characteristics of an apartment-threaded object as well as a free-threaded object. The advantage that this threading model brings is that no matter where the component is created, it will always be created within the same apartment as the object that created it. If it is created by a component running in a single-thread apartment, then it will act like an apartment-threaded component, and be created in the apartment. This means that the calls between the components can be direct and not require a slower proxy.
Likewise, if the new component is created by a component running in the multi-thread apartment, it will act like a free-threaded component and be created in the MTA. This will allow the components direct access to each other, since they are running in the same apartment. In either case, to access this new component, proxy calls are not necessary. The access can be made using fast and efficient direct function calls.