Behavior: ActiveX Control (ATL) and Multithreading
Hi guys,
I have a ATL object which is implemented in a class. Some of the class’s methods are normal ones (public or private) and some are the control’s methods. The control also has a few thread functions.
I want to know the behavior of the thread that executes the methods, with respect to the functions like Sleep() or wait functions. Like, if I have a Sleep() in one executing method, then other threads executing might call other methods of this class. Will it be blocked since a Sleep() is going on? I think it does, but what about the wait functions? Also which is the best way to do a wait without the thread being blocked?
Does it depend on the apartment model that I’ve chosen?
Thanks
Note to mods: Does this post belong to multithreading forum or VC++ forum?
[827 byte] By [
Mathew Joy] at [2007-11-19 1:29:01]

# 1 Re: Behavior: ActiveX Control (ATL) and Multithreading
I would believe it surely will have to do with the threading model you choose. Also, it would depend on whether you are operating on the same object or a different object ( same class though).
The way it works is:
1. If you set the threading model as apartment
Objects created in an STA can be accessed from that thread alone. Any call now into this object's method has to go through the apartment. And hence, if you are making 2 consective calls on the object from 2 threads, then the second call will be blocked till the first one completes ( so if you have a sleep in there.. it has to finish .. windows uses Window messages to serailize these calls ). So, you need not have to add protection to access to your object's data. All methods here execute in the context of the apartment's thread.
2. If you set the threading model as multithreaded
Each object will be created in a single apartment which is created by the first caller of CoInitializeEx with MULTITHREADED_APARTMENT. Now, all threads can access the object and it's method and no synchro is provided.. All the methods will execute in the context of the calling threads.
it is kinda confusuing.. Look at these articles.. There is a lot of info here..
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncomg/html/comthreading.asp
http://support.microsoft.com/kb/q150777/
# 2 Re: Behavior: ActiveX Control (ATL) and Multithreading
Thanks Kirants for you reply.
I was looking into the MSDN about the thread models. It is interesting that when I created a new ATL component, I got the screen below. As you can see, the free (which is what I think is MTA, before I thought Apartment was MTA) option is disabled. Why is it? Doesn’t ATL control support it? A simple object do have the options enabled though. In the code I have
public CComObjectRootEx<CComSingleThreadModel> which is how the STA COM object is inited, I guess.
# 3 Re: Behavior: ActiveX Control (ATL) and Multithreading
I changed the CComSingleThreadModel to CComMultiThreadModel and
val ThreadingModel = s 'Apartment'
to
val ThreadingModel = s 'Free' and tried in a new ATL ActiveX object with a similar scenario…and well, it worked fine…without blocking. But is this all that is need to change it to MTA? And I found that OnDraw(ATL_DRAWINFO& di),which is the provided by the wizard, was not called when changed to MTA.
Any comments about implementing the control in VB? Because the target language apart from VC is VB. Does it support MTA or will it behave like STA?
# 4 Re: Behavior: ActiveX Control (ATL) and Multithreading
I just dump a little bit information on you related to COM and threads (I also repeat some of the things kirants wrote) :
ActiveX Controls (that is GUI COM Objects) should live in a STA (Single Threaded Apartment). STA are designed to be used for GUI COM objects (for instance every STA has an invisible window associated with it).
Access to objects that live in a STA is synchronized (COM realizes this with the help of windows messages). Access to objects that live in a MTA is NOT synchronized. If you need protection from concurrent access you need to do it yourself.
If your object lives in a STA calling Sleep() will block all others objects that live in the same STA (as they share the same thread).
If you wish to wait for resources (such as reading from files and sockets) in an object that lives in a STA and not block the thread you can use MsgWaitForMultipleObjects and pump the message loop. However, then you may get reentrancy issues. Critical Sections won't
protect against reentrancy.
There are programmers that implements MTA objects in VB but it wont be easy.
If you create an ordinary non GUI COM object that should live in a MTA you might need to protect your methods from concurrent access (calling Lock and Unlock on the object or using a lock scope guard).
Even if you are doing STA objects you may need to protect access to global resources from concurrent access. This is because there may be several STA in a process each executed by a seperate thread. If you access a global resource it might access it from seperate threads. A way to side step this is to declare your objects so that they are created in the mainthread STA (which there may only be one of in every process).
The difference between CComSingleThreadModel and CComMultiThreadModel basically is this: The refcount is protected from concurrent access in the latter case. Also the method Lock() and Unlock() locks a critical section in the latter case, in the first case they are no-ops.
By setting
val ThreadingModel = s 'Free'
you make sure that your object is created in the MTA (I just wanted to verify it for you).
Things you didn't ask for but might want to know:
Calling an object that lives in an apartment from another apartment will force a thread switch. This takes time. Also if you are calling from a STA the COM framework will start pump the message loop. This may lead to reentrancy issues.
When transferring an interface pointer from one apartment to another you need to marshal it. Just a simple copy won't work. Sure it might _seem_ like it works but sometimes you will get inexplicable AVs. So for instance if you store interface pointers in an object you must make sure that they are always accessed from the right thread. To marshal an interface pointer look up: 'Global Interface Table' in MSDN or PSDK.
I hope this helps you in some way.
# 5 Re: Behavior: ActiveX Control (ATL) and Multithreading
Do you mean an ActiveX control should not live in MTA? Technically, though my ActiveX control might be a GUI object, it does no drawing at runtime. It is invisible. Nor does it pop up any window. Is that why the OnDraw() function wasn’t called? (This drawing is done only at design time not at runtime) The above couple of changes that I did will safely change the apartment mode to multithreading, right?
Thanks
# 6 Re: Behavior: ActiveX Control (ATL) and Multithreading
Do you mean an ActiveX control should not live in MTA?
Yes, this is what I meant.
If you have an object that's invisible you could consider using the "Simple Object" in the ATL Wizard. This COM object may live in a MTA. Also as a side benefit it has a smaller memory footprint as it doesn't implement all of the ActiveX interfaces (there are a few).
The above couple of changes that I did will safely change the apartment mode to multithreading, right?
As far as I know this should ensure that your object is created in the MTA and that the AddRef/Release are protected from concurrent access.
However, your own state isn't automatically protected.
# 7 Re: Behavior: ActiveX Control (ATL) and Multithreading
Yes, this is what I meant.Thanks Marten for your reply.
The object has to be an ActiveX control. Do you know if it is OK if I forcefully make it reside in an MTA? (like I did above)
# 8 Re: Behavior: ActiveX Control (ATL) and Multithreading
It would. But again, you have to take care to control access to your object's data.
# 9 Re: Behavior: ActiveX Control (ATL) and Multithreading
The object has to be an ActiveX control.
Out of interest. Why does it need to be an ActiveX control if it's invisible.
# 10 Re: Behavior: ActiveX Control (ATL) and Multithreading
Out of interest. Why does it need to be an ActiveX control if it's invisible.You may be right but that is beyond my choice :). Thanks both for your help
Good Luck :wave:
# 11 Re: Behavior: ActiveX Control (ATL) and Multithreading
cool.. Have fun :wave: