GOTCHA 69 STAThread attribute may have no effect on your methods


GOTCHA #69 STAThread attribute may have no effect on your methods

Let's continue with the discussions from Gotcha #68, "Default apartment of main thread is inconsistent across languages" You may think, "Well, I want my worker thread to be in an STA, so let me mark the method with the STAThread attribute just like it's done in Main()." Is that a good idea? Let's find out. Consider Example 8-6.

Example 8-6. Effect of using the STAThreadAttribute

C# (SettingApartment)

 using System; using System.Threading; namespace COMCompUser {     class Test     {         [STAThread]         static void Worker()         {             Thread currentThread = Thread.CurrentThread;             Console.WriteLine("In worker thread");             Console.WriteLine("Apartment in worker is {0}",                 currentThread.ApartmentState.ToString());             Console.WriteLine("Creating COM object");             MyCOMCompLib.IMyComp theMyComp                 = new MyCOMCompLib.MyCompClass();             Console.WriteLine("Apartment in worker is {0}",                 currentThread.ApartmentState.ToString());         }         [STAThread]         static void Main(string[] args)         {             Thread currentThread = Thread.CurrentThread;             Console.WriteLine("Apartment in main is {0}",                 currentThread.ApartmentState.ToString());             Console.WriteLine("Creating COM object");             MyCOMCompLib.IMyComp theMyComp                 = new MyCOMCompLib.MyCompClass();             Console.WriteLine("Apartment in main is {0}",                 currentThread.ApartmentState.ToString());             Thread workerThread = new Thread(                 new ThreadStart(Worker));             //Not setting IsBackground on thread intentionally             workerThread.Start();         }     } } 

VB.NET (SettingApartment)

 Imports System.Threading Module Test     <STAThread()> _     Private Sub Worker()         Dim currentThread As Thread = Thread.CurrentThread         Console.WriteLine("In worker thread")         Console.WriteLine("Apartment in worker is {0}", _                      currentThread.ApartmentState.ToString())         Console.WriteLine("Creating COM object")         Dim theMyComp As MyCOMCompLib.IMyComp _          = New MyCOMCompLib.MyCompClass         Console.WriteLine("Apartment in worker is {0}", _          currentThread.ApartmentState.ToString())     End Sub     <STAThread()> _     Public Sub Main()         Dim currentThread As Thread = Thread.CurrentThread         Console.WriteLine("Apartment in main is {0}", _          currentThread.ApartmentState.ToString())         Console.WriteLine("Creating COM object")         dim theMyComp as MyCOMCompLib.IMyComp _                 = new MyCOMCompLib.MyCompClass()         Console.WriteLine("Apartment in main is {0}", _          currentThread.ApartmentState.ToString())         Dim workerThread As New Thread(AddressOf Worker)         'Not setting IsBackground on thread intentionally         workerThread.Start()     End Sub End Module 

In this example, you have set the STAThread attribute on the Worker() method, which is called from a separate thread. If you expect the apartment of the thread within the Worker() method to be STA, you're in for a surprise. The output from the program is shown in Figure 8-10.

Figure 8-10. Output from Example 8-6


Even though you have set the STAThread attribute on the Worker() method, it is running in an MTA thread. How do you make Worker() run in an STA thread? The code that does that is shown in Example 8-7.

Example 8-7. Correct way to set apartment for a thread

C# (SettingApartment)

     //...     class Test     {         //[STAThread]         static void Worker()         {             //...         }         [STAThread]         static void Main(string[] args)         {             //...             Thread workerThread = new Thread(                 new ThreadStart(Worker));             //Not setting IsBackground on thread intentionally             workerThread.ApartmentState = ApartmentState.STA;             workerThread.Start();         }     } } 

VB.NET (SettingApartment)

 '... Module Test     '<STAThread()> _     Private Sub Worker()         '...     End Sub     <STAThread()> _     Public Sub Main()         '...         Dim workerThread As New Thread(AddressOf Worker)         workerThread.ApartmentState = ApartmentState.STA         'Not setting IsBackground on thread intentionally         workerThread.Start()     End Sub End Module 

As soon as you create the thread, set the ApartmentState property on it. Don't set the STAThread attribute (or the MTAThread attribute) on methods like the Worker() method. The output from this modified version is shown in Figure 8-11.

Figure 8-11. Output from Example 8-7


IN A NUTSHELL

For threads that interact with COM components, set the apartment of the thread yourself; don't use method attributes to do so.

SEE ALSO

Gotcha #67, "Cross-apartment calls are expensive," Gotcha #68, "Default apartment of main thread is inconsistent across languages," and Gotcha #70, "Spattering access to COM components makes code hard to maintain."



    .NET Gotachas
    .NET Gotachas
    ISBN: N/A
    EAN: N/A
    Year: 2005
    Pages: 126

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net