By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,574 Members | 2,960 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,574 IT Pros & Developers. It's quick & easy.

Events and threads

P: n/a
Hi there,

Are there any specific rules or best-practices I should be aware regarding
events and the threads they're fired on. Object 1 can be created on thread 1
for instance and an event then registered with it on thread 2. Object 1
might then fire the event on thread 3 and the event might later be
deregistered on thread 4. Are there any inherent problems with these (and
other) scenarios so long as the event handler is properly dealing with its
own synchronization issues. Note that I'm asking because I recently received
the exception:

"COM object that has been separated from its underlying RCW cannot be used"

This apparently occurred because I was registering and deregestering my
handler for a (native Visual Studio) event on thread 2 even though the
object firing the event was created on thread 1 (and firing on thread 1). It
even causes VS itself to consistently crash but I could later see that it
had something to do with some underlying calls to "Advise()" and
"Unadvise()" (for those familiar with COM). Apparently I must be breaking
the thread affinity rules since the problem disappears if I register and
unregister my handler on thread 1 instead. Any insight would be appreciated.
Thanks.
Sep 18 '07 #1
Share this Question
Share on Google+
3 Replies


P: n/a
JohnM,

COM has its own thread affinity rules (refered to as apartments) which
require some special handling.

You have to be aware of the apartment state required by the COM object.
For a good majority of them, they require an STA apartment, meaning that
they are attuned to the thread that they are created on, and calls are
marshaled back into that thread.

Now, with event handlers, you are trying to access that STA object on
another thread. When making calls to other components in other threads, you
have to marshal the call correctly, which usually involves a call to
CoMarshalInterThreadInterfaceInStream (a COM API call) so that you can
correctly marshal the call between apartments and threads. I would be
willing to bet that this is the case here.

The easy solution is to make sure that you make all the calls to the
component on the thread that they are called in. If you need to make the
calls on other threads, then you are probably going to have to use the
unmanaged CoMarshalInterThreadInterfaceInStream and
CoGetInterfaceAndReleaseStream API methods to correctly marshal the
interface to the other threads to call. Also, you have to make sure that
those threads are initialized for COM (using the SetApartmentState method on
the Thread, which could be an issue if you are using ThreadPool threads,
since the apartment state can only be set once and the thread will
eventually be used for other purposes).

Even if you do marshal the interface pointers correctly, the calls, when
made on another thread, will still be marshaled to the main thread (assuming
it is an STA component, which I am), so unless you are doing considerable
other work on those threads, it won't be worth it.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com

"JohnM" <no_spam@_nospam.comwrote in message
news:%2********************@TK2MSFTNGP04.phx.gbl.. .
Hi there,

Are there any specific rules or best-practices I should be aware regarding
events and the threads they're fired on. Object 1 can be created on thread
1 for instance and an event then registered with it on thread 2. Object 1
might then fire the event on thread 3 and the event might later be
deregistered on thread 4. Are there any inherent problems with these (and
other) scenarios so long as the event handler is properly dealing with its
own synchronization issues. Note that I'm asking because I recently
received the exception:

"COM object that has been separated from its underlying RCW cannot be
used"

This apparently occurred because I was registering and deregestering my
handler for a (native Visual Studio) event on thread 2 even though the
object firing the event was created on thread 1 (and firing on thread 1).
It even causes VS itself to consistently crash but I could later see that
it had something to do with some underlying calls to "Advise()" and
"Unadvise()" (for those familiar with COM). Apparently I must be breaking
the thread affinity rules since the problem disappears if I register and
unregister my handler on thread 1 instead. Any insight would be
appreciated. Thanks.

Sep 18 '07 #2

P: n/a
COM has its own thread affinity rules (refered to as apartments) which
require some special handling.

You have to be aware of the apartment state required by the COM object.
For a good majority of them, they require an STA apartment, meaning that
they are attuned to the thread that they are created on, and calls are
marshaled back into that thread.

Now, with event handlers, you are trying to access that STA object on
another thread. When making calls to other components in other threads,
you have to marshal the call correctly, which usually involves a call to
CoMarshalInterThreadInterfaceInStream (a COM API call) so that you can
correctly marshal the call between apartments and threads. I would be
willing to bet that this is the case here.

The easy solution is to make sure that you make all the calls to the
component on the thread that they are called in. If you need to make the
calls on other threads, then you are probably going to have to use the
unmanaged CoMarshalInterThreadInterfaceInStream and
CoGetInterfaceAndReleaseStream API methods to correctly marshal the
interface to the other threads to call. Also, you have to make sure that
those threads are initialized for COM (using the SetApartmentState method
on the Thread, which could be an issue if you are using ThreadPool
threads, since the apartment state can only be set once and the thread
will eventually be used for other purposes).

Even if you do marshal the interface pointers correctly, the calls,
when made on another thread, will still be marshaled to the main thread
(assuming it is an STA component, which I am), so unless you are doing
considerable other work on those threads, it won't be worth it.
Thanks for the info. I'm very familiar with the COM issues you mentioned but
(obviously) have much less .NET experience (my background is C++ and the
WinAPI). The object firing the event in this case is a native member of the
Visual Studio extensibility API which is used for writing VS AddIns (which
I'm now working on). I'm working with the .NET classes directly however so
even if the underyling objects are COM objects, I would have thought that
all the marshalling would have been handled by .NET (since the underlying
COM objects are implementation details which I shouldn't even be aware of).
Apparently not so I have no (practical) choice but to register/unregister my
events on the same thread the object firing the event is created on. This
makes things more difficult noting that these objects are handed to me by VS
on the main thread so I have no say in when they're created (but I later
need to register my events on another thread). In any case, is this normal
behaviour. That is, can you normally register/unregister a .NET event on a
different thread than the object firing the event is created on. If so then
how is someone supposed to know if it's really safe or not given this
experience (i.e., the error mentioned in my first post happens most of the
time but not always - in theory it might not have surfaced until the program
was actually on a customer's machine). Thanks again.
Sep 18 '07 #3

P: n/a
It's not a bug, it's just that it is expected that the user set up the
apartment state correctly, and manage the interface pointers when
transferring them across threads. The same rules that applied in COM
apply in .NET as well when using COM, and it is up to the developer to
handle that situation. It is not automatically done for you.
Perhaps you're right. However, from the programmer's perspective COM doesn't
come into play here. It's .NET we're working with and COM is rarely ever
mentioned in the .NET literature (for the extensibility API). For someone
with no background in COM in particular, or who has never even heard of
marshalling, it would make no difference to them. There's really just an
assumption that all the plumbing is handled automatically. Even in my own
case, with many years of experience, I wasn't sure if I was doing something
wrong or if there was really a bug. While I knew early on there was a COM
marshalling problem, this is something that many others wouldn't have
recognized without a COM background. Nevertheless, it was still unclear
whether I should be expeirncing it given that .NET was in the driver's seat.
I'll just have to do some more reading on the subject now that you've
enlightened me. Thanks again.
Sep 18 '07 #4

This discussion thread is closed

Replies have been disabled for this discussion.