开发者

STA (Single Threaded Apartment) COM Object - Spawn worker threads?

Is it a bad thing to spawn worker threads in your STA COM object (ie. COM object creates a thread to perform a task)? I think, the answer is - that depends!

For example in my case: The worker threads that I am using will not interfere/access COM or COM Services.

Reason why I am asking this is because by ST开发者_开发知识库A COM definition STA can only house one thread. Spawning multiple threads kind of goes against this principle unless the worker threads and the work they do NOT interfere/deal with COM/COM services. In this case I am thinking this is perfectly fine and in my opinion the worker threads should not be considered by COM as part of the logical STA.

What are your thoughts on this?


No, that's not a bad thing. Apartments explicitly exist to help you getting multi-threaded code working. An STA thread is a safe home for a COM server that's not thread-safe, COM's apartment threading model ensures that it is always used in a thread-safe way. All you have to do is the marshal the interface pointer you want to use in the worker thread (IGlobalInterfaceTable for example) and you can call the methods without doing anything special.

This doesn't come for free of course, there's overhead involved in marshaling the call. How much depends on how responsive the STA thread is when it pumps its message loop. If you intended to create the worker thread explicitly to use that COM server in a multi-threaded way then of course you'll not be ahead, you made it slower.


Don't let the worker threads use COM in any way, and you should be fine. This means you can't call COM objects in the worker and you can't call COM runtime APIs from the worker... either directly or indirectly.


The important thing to realize is that any new threads you create are new threads in their own right; it actually doesn't matter at all which thread created them. The two things that matter are: (1) that those new threads themselves call CoInitializeEx and either get their own STA each, or share an MTA together, and (2) any COM object pointers you transfer between threads get marshaled appropriately. Do not ever just pass a COM object pointer from one thread to another in a global variable; instead use the GIT or CoMarshalInterThreadInterfaceInStream as appropriate.

(One exception to this: you can pass COM pointers freely between MTA threads; but only once that pointer has been appropriately marshaled into the MTA in the first place.)

Also, you need to be very aware of there objects live and what their affinities are. If you create an object on a STA thread, and marshal a pointer to another thread, then the typical case is that the object will still live on that original STA thread with calls returning to that thread, unless you takes specific steps to specify otherwise. (Things to watch for here: what the object's threading model is, and whether it 'aggregates the free-threaded marshaller'.)

So it's not a bad thing; but be sure that you do it appropriately. For example, you might think that using two threads might be more efficient; but then later on realize that a lot of time is being spent by that worker thread calling back to the object on the original thread, giving you worse performance than a single-threaded case. So you need to think out your threads and object strategy carefully first.

(Having said all of that, you can of course spin up as many threads as you want that don't call CoInitialize, so long as they don't use COM or COM objects in any way; if those threads to need so somehow communicate with the threads that do use COM, it's up to you to manage that communication using any 'classic' IPC mechanism of your choice - eg. messages, globals, etc.)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜