Click here to Skip to main content
Click here to Skip to main content

STA threading model issues

By , 16 May 2001
 

Introduction

Here are two things that I think developers should be aware of when programming with STA threading model. I'm not trying to cover all pitfalls that one might encounter, but only specific two that I thought can bite developers..

Project: "Create an ActiveX component for some or other purpose."

At first I started with a simple ActiveX component using "Apartment" threading model. Then added another COM class, which will be passed to one of the events as argument. Created an events thread to fire the events to client. All seemed to work fine. I wrote various simple apps that tested the functionality in ATL/WTL, MFC, VB, and VBScript/JScript all using same threading model.

STA Deadlock

Then I've tried MTA for the container. Suddenly, it started to deadlock randomly. Why? I thought if it works for STA what difference does it make if the container is STA or MTA? COM should intervene and take care of apartment incompatibilities. It took some quick research to find the problem. Thanks to Valery Pryamikov's post on ATL list, "Designing Solutions with COM+ Technologies" (pp. 96-97) and "Transactional COM+" (pp. 130-131) things started to make sense. I've made a stripped down version that shows the problem and you can download the STA Deadlock sample project. Please run it in the debugger. The deadlock will happen when you quit the app. Notice that if you change the client's threading model to "Apartment" or in-proc COM server to "Both" everything works. The problem comes from the fact that client makes an outgoing call back on the COM component passed in the event's function. Now, if at the same time client calls back into main component for whatever reason and blocks with message loop (i.e. to shutdown events thread in the component while Unadvise is called), there will be a deadlock. When the client called back on the ISimpleObj methods, "channel" is already taken by the Unadvise where I tried to shutdown the events thread. So, both threads will be waiting for each other to get a hold of the "channel". It's just one scenario where the deadlock could happen and can easily be accomplished other ways. The nasty thing about this is that it may not happen all the time and may not happen at all. It all depends on the right circumstances. So be aware.

STA Reentrancy

This is widely known, but I just wanted to show it anyway because I never saw concrete examples when I was starting with COM. Maybe someone will find it helpful. So, after dealing with deadlock I got bitten by the STA reentrancy. The component was using windows sockets to communicate with the server. Now, that I've marked my component as "Both" and synchronized all access to the component I thought I'm safe...But...One of the methods is taking an interface pointer that is part of some object. Now, inside the method I call methods on the interface and send data out over the socket. Unfortunately, when I make the outgoing call on another component, "STA reentrancy model" will yield the thread to another incoming call if there is any. It can happen if client decides to call my method from the thread different from the object's creating thread. I can't assume that clients will do the right thing. So, this was unacceptable because the actual server that my component communicates with over sockets, expects a specific flow of information. I've made a simple project that shows it in action using file instead of sockets. Look at STA Reentrancy if you run it, you'll see that the output to log file is mixed up instead of having a sequential flow. Notice that if you change the client's threading model to MTA it will work fine. COM will come in and take care of synchronization for us.

After dealing with "Apartment", "Both", and "Free" I would take MTA anytime over STA model - if possible of course. I hope someone finds this article helpful.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Leon Finker
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralCOMmemberSeethalakshmi2 Sep '05 - 23:39 
Please let me know how to know what threading model a project uses ? Also, let me know in detail the available threading models in VB.
 
Seethalakshmi A
GeneralRe: COMmemberJessn2 Nov '06 - 11:28 

In visual basic 6.0 it uses STA as the default. When using C++ you have the option to choose between STA and MTA. A rule of thumb is not to mixed the two models otherwise you will end up with unpredictable results and it will be harder to repro any possible errors because of this.
 
I do agree with the author that the MTA model is the one to use whenever it is possible.
 


 
--
Jess Nielsen
Security Analyst
C++ Programmer

GeneralServer\clients problemsussPascal75855 Jul '05 - 7:35 
Hello,
 
I created an COM (.exe) in STA. I would like to use it to shared data between different software.
I also created a client which call the COM.
until now no problem, when I start the client I access the COM, I can write and read in it.
 
but when I start another client. I click to read the value: it is not the value I wrote in the first client.
 
do you have some ideas to help me??
 
thank you in advance.
 
Pascal.
GeneralRe: Server\clients problemmemberLeon Finker5 Jul '05 - 13:46 
Hi,
 
Please refer to:
 
Q I want to implement a singleton object in COM. How should I do it?
http://www.microsoft.com/msj/0797/activex0797.aspx

GeneralRPC_E_WRONG_THREADmemberPriyank Bolia13 May '04 - 1:06 
I have an COleDispatchDriver pointer in the main thread, and I am calling the InvokeHelper in another thread, then it is returning this error: RPC_E_WRONG_THREAD, the ::OleInitialize(NULL); has been done in the sub thread. Can anyone has some solution for this problem.
 
http://www.geocities.com/priyank_bolia/

 

GeneralRe: RPC_E_WRONG_THREADmemberLeon Finker13 May '04 - 1:16 
Hi,
 
"How To Marshal Interfaces Across Apartments"
http://support.microsoft.com/default.aspx?scid=206076
GeneralRe: RPC_E_WRONG_THREADmemberPriyank Bolia13 May '04 - 3:03 
I can't understand that article, the problem is that I have a COleDispatchDriver pointer in the main thread : COleDispatchDriver *m_pVicApp which is used in some other thread to call InvokeHelper for the server function, whose code I don't have.
 
http://www.geocities.com/priyank_bolia/

GeneralRe: RPC_E_WRONG_THREADmemberLeon Finker13 May '04 - 4:20 
Before using COleDispatchDriver pointer in another thread, the real COM interface pointer has to be marshaled to another thread. Before making the call you unmarshal the COM interface pointer and make the call on that pointer. That article describes a number of ways on how you you can do the actual marshaling.
GeneralRe: RPC_E_WRONG_THREADsussAnonymous5 Apr '05 - 22:06 
Hi, Can you try to use ::CoInitializeEx() with COINIT_APARTMENTTHREADED parameter instead of ::OleInitialize(NULL); This is very interesting problem. Thread models are very important. For instance If you initialize your software by wrong parameter you might get some problems. Probably you get some errors while your long process when you use ADO components, or common dialog boxs might failed in some operating systems.
GeneralI Think..................memberzhenguri6 Aug '01 - 16:21 
if your two object created in same STA, no reenter HAPPEN..........
 
Confused | :confused:

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 17 May 2001
Article Copyright 2001 by Leon Finker
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid