Discussion:
DCOM calls from thread pool threads
(too old to reply)
Dilip
2006-07-19 16:49:11 UTC
Permalink
I need to make a DCOM call from thread pool threads that were spun off
using QueueUserWorkItem. IOW, the callback function used by the thread
pool in console application 1 needs to call an interface method on a
COM object hosted in an out-of-proc COM server every now & then. This
out-of-proc server is completely free threaded (so no hairy STA related
issues).

my question is COM rules mandate that every thread that wants to make a
(D)COM call needs to call CoInitialize/CoUninitialize, right? Every
thread needs to enter an apartment before it can make a COM call, so
even if there is going to be only one MTA per process, a thread still
needs to enter it, right?

since I can't rely on the same thread pool thread executing my callback
function, do I need to call CoI/CoUni pair before every method call?
That somehow doesn't sound logical.

I was wondering if I could just create the said COM object as a global
object, let the main (primary) thread enter MTA using
COINIT_MULTITHREADED and let all those thread pool threads simply
access the global object. Will this create a problem exactly when I
demo it to my boss?
SteveS
2006-07-19 17:10:02 UTC
Permalink
Post by Dilip
I need to make a DCOM call from thread pool threads that were spun off
using QueueUserWorkItem. IOW, the callback function used by the thread
pool in console application 1 needs to call an interface method on a
COM object hosted in an out-of-proc COM server every now & then. This
out-of-proc server is completely free threaded (so no hairy STA related
issues).
my question is COM rules mandate that every thread that wants to make a
(D)COM call needs to call CoInitialize/CoUninitialize, right? Every
thread needs to enter an apartment before it can make a COM call, so
even if there is going to be only one MTA per process, a thread still
needs to enter it, right?
since I can't rely on the same thread pool thread executing my callback
function, do I need to call CoI/CoUni pair before every method call?
That somehow doesn't sound logical.
I was wondering if I could just create the said COM object as a global
object, let the main (primary) thread enter MTA using
COINIT_MULTITHREADED and let all those thread pool threads simply
access the global object. Will this create a problem exactly when I
demo it to my boss?
You've answered your own question; every thread must call
CoInitialize/CoInitializeEx before making a COM (or DCOM) call, and before
the thread exits, must call CoUnitialize.

If it was me, I'd call CoInitialize* at the start, and call CoUninitialize
before returning. Expensive, but necessary (unless someone who knows what
they're talking about comes along and provides an alternative!)
--
Steve S
Dilip
2006-07-19 17:19:59 UTC
Permalink
Post by SteveS
You've answered your own question; every thread must call
CoInitialize/CoInitializeEx before making a COM (or DCOM) call, and before
the thread exits, must call CoUnitialize.
If it was me, I'd call CoInitialize* at the start, and call CoUninitialize
before returning. Expensive, but necessary (unless someone who knows what
they're talking about comes along and provides an alternative!)
Thanks! I feared this would be true. The callback function itself
shouldnt' take more than a few milliseconds to complete, the problem is
I will probably queue literally *millions* of work items and every such
item executed by this callback func translates to million
CoInitialize/CoUninitialize calls. Surely I must be missing something
here, right?
Brian Muth
2006-07-19 17:32:45 UTC
Permalink
Post by Dilip
Post by SteveS
You've answered your own question; every thread must call
CoInitialize/CoInitializeEx before making a COM (or DCOM) call, and before
the thread exits, must call CoUnitialize.
If it was me, I'd call CoInitialize* at the start, and call
CoUninitialize
before returning. Expensive, but necessary (unless someone who knows what
they're talking about comes along and provides an alternative!)
Thanks! I feared this would be true. The callback function itself
shouldnt' take more than a few milliseconds to complete, the problem is
I will probably queue literally *millions* of work items and every such
item executed by this callback func translates to million
CoInitialize/CoUninitialize calls. Surely I must be missing something
here, right?
In this case, I'd suggest managing your own thread pool. This way you can
call CoInitializeEx and CoCreateInstanceEx when the threads are first
created. This would be substantially faster.

Brian
Dilip
2006-07-19 17:43:33 UTC
Permalink
Post by Brian Muth
Post by Dilip
Post by SteveS
You've answered your own question; every thread must call
CoInitialize/CoInitializeEx before making a COM (or DCOM) call, and before
the thread exits, must call CoUnitialize.
If it was me, I'd call CoInitialize* at the start, and call
CoUninitialize
before returning. Expensive, but necessary (unless someone who knows what
they're talking about comes along and provides an alternative!)
Thanks! I feared this would be true. The callback function itself
shouldnt' take more than a few milliseconds to complete, the problem is
I will probably queue literally *millions* of work items and every such
item executed by this callback func translates to million
CoInitialize/CoUninitialize calls. Surely I must be missing something
here, right?
In this case, I'd suggest managing your own thread pool. This way you can
call CoInitializeEx and CoCreateInstanceEx when the threads are first
created. This would be substantially faster.
CoCreateInstance would be called only once anyway -- from the main
thread by entering COINIT_MULTITHREADED (since I am planning to keep
the COM object global). So, short of implementing your own thread pool
there simply is no way that built in thread pool threads can correctly
make (D)COM calls? Somehow I can't believe MS didn't anticipate that!
:-(
Brian Muth
2006-07-19 19:42:56 UTC
Permalink
Post by Dilip
Post by Brian Muth
Post by Dilip
Post by SteveS
You've answered your own question; every thread must call
CoInitialize/CoInitializeEx before making a COM (or DCOM) call, and before
the thread exits, must call CoUnitialize.
If it was me, I'd call CoInitialize* at the start, and call CoUninitialize
before returning. Expensive, but necessary (unless someone who knows what
they're talking about comes along and provides an alternative!)
Thanks! I feared this would be true. The callback function itself
shouldnt' take more than a few milliseconds to complete, the problem is
I will probably queue literally *millions* of work items and every such
item executed by this callback func translates to million
CoInitialize/CoUninitialize calls. Surely I must be missing something
here, right?
In this case, I'd suggest managing your own thread pool. This way you can
call CoInitializeEx and CoCreateInstanceEx when the threads are first
created. This would be substantially faster.
CoCreateInstance would be called only once anyway -- from the main
thread by entering COINIT_MULTITHREADED (since I am planning to keep
the COM object global). So, short of implementing your own thread pool
there simply is no way that built in thread pool threads can correctly
make (D)COM calls? Somehow I can't believe MS didn't anticipate that!
There is nothing stopping you from using the thread pool provided via
QueueUserWorkItem. It's just that each thread must call CoInitialize to join
the apartment of your choosing.

I don't think the problem is Microsoft's. It's more a matter of choosing
your tools correctly. QueueUserWorkItem is probably not the right choice for
your project.

Brian
Dilip
2006-07-25 22:59:06 UTC
Permalink
I found this little nugget:

"NOTE: Current implementations of COM allow a thread that does not
explicitly initialize COM to be a part of the MTA. A thread that does
not initialize COM is part of the MTA only if it starts using COM after
at least one other thread in the process has previously called
CoInitializeEx(NULL, COINIT_MULTITHREADED). (It is even possible that
COM itself may have initialized the MTA when no client thread has
explicitly done so; for example, a thread associated with an STA calls
CoGetClassObject/CoCreateInstance[Ex] on a CLSID that is marked
"ThreadingModel=Free" and COM implicitly creates an MTA into which the
class object is loaded.) See the information on threading model
interoperability below.

However, this is a configuration that might cause problems, such as
access violations, under certain circumstances. Therefore, it is
strongly recommended that each thread that needs to do COM work
initialize COM by calling CoInitializeEx and then, on completion of COM
work, call CoUninitialize. The cost of "unnecessarily" initializing an
MTA is minimal."

here: http://support.microsoft.com/kb/150777/

So it looks like the cost of doing a CoInit under MTA is very minimal.
I can live with that.

Loading...