Ticket #198 (closed defect: fixed)
COM object creation should adhere to threading model
Reported by: | jasper | Owned by: | jasper |
---|---|---|---|
Priority: | major | Milestone: | Phase III WP1 |
Component: | COBIA core | Version: | 1.2.0.14 |
Keywords: | Cc: |
Description
COM objects that are crated from COBIA should be created in accordance with threading model memo
Attachments
Change History
Changed 8 months ago by jasper
- Attachment Guidelines-For-Threading_CP.pdf added
Threading memo (draft)
comment:2 Changed 8 months ago by jasper
I would like to point out that in the scenario in which a COBIA PME does not initialize COM on the current thread, and asks for creation of an out-of-process COM object (e.g. a LocalServer?), it will be double-marshaled:
- because we may not initialize COM on the current thread, COBIA will have to create the object in a COBIA marshaling thread, which is the first marshaling that occurs
- COM will subsequently marshal a second time because the object itself is out of process.
I do not see a work around for this situation - let's hope nobody creates out-of-process COM servers.
Implementation details:
- Single threaded thread pool threads always initialize COM as apartment threaded on Windows
- Multi-threaded pool threads always initialize COM as multi-threaded on Windows
- COINIT_SPEED_OVER_MEMORY is specified at COM initialization
- if COM initialization fails, this is not flagged - as the thread may want to create non-COM objects in any case. However, in this scenario CoCreateInstance? will fail, as there is nothing else on the thread that initializes COM. We will have very few diagnostics at this point why CoCreateInstance? fails other than that it will say that COM is not initialized.
- if COM initialization succeeds, it is cleaned up when the thread pool thread exists
- as the PME initializes COM, or COM is initialized by the marshaler threads, the COM initialization has been removed from COMBIA
There are no structural tests in place. I ran COM objects in the ThermoClientPME to check that all goes well. Then I added COM initialization to the ThermoClientPME and checked that all goes well. So one-off testing has been done. The ThermoClientPME example got the following code:
#ifdef _WIN32 //On Windows we initialize COM to prevent that COBIA is forced to create // COM objects in a marshaling thread (on which COBIA is free to initialize // COM itself - it cannot do so on a PME thread). //This particular application is a single threaded application and only // uses COM objects in the main thread; additionally it specifies // CapePMCCreationFlag_AllowRestrictedThreading on all PMC creation. //We initialize COM as Apartmnent threaded accordingly so that COM // objects with threading models "Apartment" and "Both" can be created // without marshaling. class COMInitializer { public: COMInitializer() { CoInitializeEx(NULL,COINIT_APARTMENTTHREADED); } ~COMInitializer() { CoUninitialize(); } }; #else //does nothing if not on Windows class COMInitializer { }; #endif
An instance of COMInitializer is created in the main thread. It is verified that no marshaling occures for Apartment threaded COM objects in this scenario.
As described in WAF-10