Visual Basic Concepts
In Visual Basic, apartment-model threading is used to provide thread safety. In apartment-model threading, each thread is like an apartment — all objects created on the thread live in this apartment, and are unaware of objects in other apartments.
Visual Basic’s implementation of apartment-model threading eliminates conflicts in accessing global data from multiple threads by giving each apartment its own copy of global data, as shown in Figure 8.3.
Figure 8.3 Each thread has its own copy of global data
This means that you cannot use global data to communicate between objects on different threads.
Note Objects in different apartments can only communicate with each other if a client passes them references to each other. In this case, cross-thread marshaling is used to provide synchronization. Cross-thread marshaling is almost as slow as cross-process marshaling.
Note 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 thread. This is discussed further in "Designing Thread-Safe DLLs" and "Designing Multithreaded Out-of-Process Components."
All components created with Visual Basic use the apartment model, whether they’re single-threaded or multithreaded. A single-threaded component has only one apartment, which contains all the objects the component provides.
This means that a single-threaded DLL created with Visual Basic is safe to use with a multithreaded client. However, there’s 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. This is discussed in "Designing Thread-Safe DLLs."
A multithreaded in-process component has no threads of its own. The threads that define each apartment belong to the client, as explained in "Designing Thread-Safe DLLs."
By contrast, a multithreaded out-of-process component may have a thread pool with a fixed number of threads, or a separate thread for each externally created object. This is discussed in "Designing Multithreaded Out-of-Process Components."
In addition to maintaining a separate copy of your global data for each thread, Visual Basic maintains separate copies of the data supplied by global objects such as the App object. Thus the ThreadID property of the App object will always return the Win32 thread ID of the thread on which the property call was handled.
Unlike earlier versions of Visual Basic, projects authored with Visual Basic 6 can take advantage of apartment-model threading without having to suppress visual elements such as forms and controls. Forms, UserControls, UserDocuments, and ActiveX designers are all thread-safe. You can select a setting for the Threading Model option without marking your project for Unattended Execution.
To set the threading model for an ActiveX DLL, ActiveX Exe, or ActiveX Control project
Note When you change the threading model for an existing project, an error will occur if the project uses single-threaded ActiveX controls. Visual Basic prevents the use of single-threaded controls in apartment-threaded projects, as described in "Converting Existing Projects to Apartment-Model Threading" below.
Note When you specify Thread per Object (or a thread pool greater than one) for an ActiveX Exe project, only externally created objects are created on new threads. (See "Designing Multithreaded Out-of-Process Components.") Thread per Object and Thread Pool are not available for ActiveX DLL and ActiveX Control projects, because thread creation is controlled by the client application.
Important For Professional and Enterprise Edition users, the consequences of selecting Thread per Object or Thread Pool are discussed in detail in "Designing Multithreaded Out-of-Process Components."
Unattended Execution allows you to create components that can run without operator intervention on network servers. Selecting Unattended Execution doesn't affect the threading model of your component.
To mark your ActiveX DLL or EXE project for unattended execution
Important Selecting the Unattended Execution option suppresses all forms of user interaction — including message boxes and system error dialogs. This is discussed in "Event Logging for Multithreaded Components."
The following limitations apply to apartment-model threading in Visual Basic.
You can add apartment threading to your existing projects by changing the Threading Model option, as described in Selecting a Threading Model for Your Project, and recompiling the project. For many projects, this is all you need to do.
If an existing ActiveX DLL, ActiveX EXE, or ActiveX Control project uses single-threaded constituent controls, attempting to change Threading Model to Apartment Threaded will cause an error. Because of the number and severity of problems that single-threaded ActiveX controls cause for multithreaded clients, Visual Basic does not permit them to be used in ActiveX component projects.
If you have an existing project that employs a single-threaded control, contact the vendor to see whether an apartment-threaded version is available.
It is possible to trick Visual Basic into using a single-threaded control in an apartment-threaded project, by manually editing the .vbp file. Do not do this. The problems that single-threaded ActiveX controls can cause include:
Important Single-threaded controls can cause these and other problems in any multithreaded component or application you build, using Visual Basic or any other development tool.
In the apartment model, reentrancy refers to the following sequence of events:
The new request may be for the member the thread was already executing — in which case the thread enters the member a second time — or it may be for another member. If the second member doesn’t yield, it will finish processing before the first member. If it changes module-level data the first member was using, the result may be unfortunate.
By serializing property and method calls for each apartment, Automation protects you from reentrancy — unless your code yields control of the processor. Ways in which your code can yield control of the processor include:
Unless you’ve carefully written all of an object’s code so that it doesn’t matter whether two members are executing at the same time, you should not include code that yields control of the processor.
For More Information Apartment-model threading affects in-process and out-of-process components differently, as described in "Designing Thread-Safe DLLs" and "Designing Multithreaded Out-of-Process Components."