SYSK 99: Is [MTAThread] the Only Solution?


By default, Windows apps (WinForms) are marked with STAThread attribute (see Program.cs). So, if you call System.Threading.WaitHandle.WaitAll passing more than one handle in the array you’ll get an exception “WaitAll for multiple handles on an STA thread is not supported”.  I’ve seen some posts suggesting you change your application’s apartment mode to MTA.  While that solution will work, it may cause problems when using single threaded ActiveX controls, as well as any COM interactions with a single threaded apartment will now cause cross-apartment marshalling, etc.


 


An alternative is to create a thread that’ll call other methods and wait for their return, and the main thread should wait for that thread to finish execution (WaitOne).


 


Here is a code snippet that explains what I mean:


 


This code will throw an exception:


 


public class WorkerClass


{


    public System.Threading.ManualResetEvent Done = new System.Threading.ManualResetEvent(false);


  


    public void DoSomething(object data)


    {      


        Done.Set();


    }


}


 


. . .


 


WorkerClass c1 = new WorkerClass();


System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(c1.DoSomething));


WorkerClass c2 = new WorkerClass();


System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(c2.DoSomething));


 


System.Threading.WaitHandle.WaitAll(new System.Threading.WaitHandle[] { c1.Done, c2.Done });


 


 


But this won’t:


 


. . .


 


IAsyncResult ar1 = new System.Threading.WaitCallback(ExecuteAsync).BeginInvoke(null, null, this);


ar1.AsyncWaitHandle.WaitOne();


 


 


private void ExecuteAsync(object data)


{


    WorkerClass c1 = new WorkerClass();


    System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(c1.DoSomething));


    WorkerClass c2 = new WorkerClass();


    System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(c2.DoSomething));


 


    System.Threading.WaitHandle.WaitAll(new System.Threading.WaitHandle[] { c1.Done, c2.Done });


}


 


 


Now you know…


 

Comments (3)

  1. Peter Ritchie says:

    I assume by "Windows apps" you mean WinForms apps?

    MTAThread is not supported in WinForms applications.  It’s more than simply being able to use ActiveX or COM objects within the application.  The whole WinForms message pump relies on being in STA, especially when dealing with File dialogs or clipboard operations.  Switching to MTA will eventually cause a WinForms application to fail.  FxCop will catch the MTAThread attribute.

    see http://blogs.msdn.com/jfoscoding/archive/2005/04/07/406341.aspx

  2. Goyo says:

    REALLY USEFUL POST; I just had met exactly this problem. Thanks a lot.

  3. NN says:

    i asume that in the first example you are calling WaitHandle.WaitAll from a thread that is running on STA. that's why you get an exception.

    In the second example, you call WaitHandle.WaitAll from a WaitCallback. A WaitCallback is a method that execute on the ThreadPool. All ThreadPool threads are in the multithreaded apartment. Then you can call WaitHandle.WaitAll without get an exception.

Skip to main content