What Does [Stathread] Do

What does [STAThread] do?

The STAThreadAttribute is essentially a requirement for the Windows message pump to communicate with COM components. Although core Windows Forms does not use COM, many components of the OS such as system dialogs do use this technology.

MSDN explains the reason in slightly more detail:

STAThreadAttribute indicates that the
COM threading model for the
application is single-threaded
apartment. This attribute must be
present on the entry point of any
application that uses Windows Forms;
if it is omitted, the Windows
components might not work correctly.
If the attribute is not present, the
application uses the multithreaded
apartment model, which is not
supported for Windows Forms.

This blog post (Why is STAThread required?) also explains the requirement quite well. If you want a more in-depth view as to how the threading model works at the CLR level, see this MSDN Magazine article from June 2004 (Archived, Apr. 2009).

STAThread and multithreading

Apartment threading is a COM concept; if you're not using COM, and none of the APIs you call use COM "under the covers", then you don't need to worry about apartments.

If you do need to be aware of apartments, then the details can get a little complicated; a probably-oversimplified version is that COM objects tagged as STA must be run on an STAThread, and COM objects marked MTA must be run on an MTA thread. Using these rules, COM can optimize calls between these different objects, avoiding marshaling where it isn't necessary.

Starting an STAThread in C#

Thread thread = new Thread(() => MyClass.DoX("abc", "def"));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

If you need the value, you can "capture" that back into a variable, but note that the variable won't have the value until the end of the other thread:

int retVal = 0;
Thread thread = new Thread(() => {
retVal = MyClass.DoX("abc", "def");
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

or perhaps simpler:

Thread thread = new Thread(() => {
int retVal = MyClass.DoX("abc", "def");
// do something with retVal
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

Why are WinForms applications STAThread by default?

1. Why is this attribute added?

Because it is required by the ActiveX object model. And you can drop ActiveX controls on a WinForm (so it is there for compatibility) OR some .NET classes use native controls which require that attribute.

2. What does it mean?

It means the thread runs in the single-threaded apartment model.

3. What happens if you remove this attribute?

If the attribute is removed, the behavior is undefined. The program may fail at random, with sometimes sensible error messages. For example, things may work now, then break with a service pack.

How will STAThread affect my multi-threaded program

[STAThread] or Thread.SetApartmentState() are a really, really big deal. You make a promise to the operating system that you write code that is well-behaved. It matters to lots and lots of code inside Windows as well as components you use that are not thread-safe. Standard examples of such code are the Clipboard, Drag + Drop, the shell dialogs (like OpenFileDialog), components like WebBrowser and many Windows sub-components that are wrapped by .NET classes.

Thread-safety is always a big deal, writing truly thread-safe code is very, very difficult. The .NET Framework itself accomplishes it very rarely. Very basic classes list List<> are not thread-safe.

By making the promise to behave well, you must abide by the rules of writing code in a thread that reports itself to be an STA thread. You must do two basic things:

  1. You must pump a message loop. Aka Application.Run() in a Winforms or WPF app. A message loop is a basic mechanism by which you can get code to run on a specific thread. It is the universal solution to the producer-consumer problem. Which solves the thread-safety problem, if you call thread-unsafe code always from the same thread then it isn't unsafe anymore.

  2. You must never block your thread. Blocking an STA thread is very likely to cause deadlock. Because it stops those chunks of code that are not thread-safe from being called. There is core support for this in the CLR, blocking an STA thread with WaitOne() causes it to pump a message loop itself.

These requirements are easily met in a Winforms or WPF app. They are class libraries that were completely designed to help you implement them. Almost every single aspect about the way they behave was affected by it.

You must mark the Main() method in a GUI app as [STAThread]. Rock-hard requirement when it creates windows.

Creating another thread that displays a window is supported and possible. This time you must call SetApartmentState() to switch to STA, it cannot be a thread-pool thread. Getting this right is very difficult, in Winforms you'll get bitten badly by the SystemEvents class if you use certain kind of controls. It has a knack to start raising its events on the wrong thread. Debugging such a problem requires black-belt skills that look like this. That's suppose to scare you.

STATHREAD and main thread

STAThread is for the primary UI thread.

In Windows, the Single Threaded Apartment (STA) implies that (in simple terms) a Windows message pump will cooperatively manage the UI.

The attribute tells the app to create an STA thread effectively for the first/main UI thread. The other threads are effectively running in parallel to this thread and they need to ensure that when they make calls to UI components, they pass them as messages through the message pump in STA.

Now lots of people will talk about it being a COM requirement and this is true. This is because at its core, the STA threading model for COM uses Windows message pumps and is required for communication with a lot of the Windows UI.

There is good answer here too: Why do all Winforms programs require the [STAThread] attribute?

How to handle {STAThread] in C# 9 Using Top-Level Program.cs

using System.Threading;
using System.Windows.Forms;
using MapLines;

var thread = new Thread(() =>
{
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

Why does WPF require a STAThread attribute to be applied to the Main method?

This is more a Windows requirement than a WPF one, and goes back to the original design of Windows forms and controls, from before .NET.

STAThread refers to "Single-Threaded Apartments" which refers to the threading model used by the current (main) thread. The threading model in use dictates how other .NET and COM applications will talk to your application (and inherently, its threads). The single-threaded application model requires that no single object "live in" more than one STA thread at a time, verses the MTA thread model; and allows for the passing of pointers to data across apartments only via marshalling-as-object.

Basically, with the [STAThread] declaration, other applications will know what your thread's policy is when sending you data. The STA model is the most common threading model for Windows threads/applications; but you'll sometimes come across certain code that won't run if called from an STA-modeled thread, because it's designed to send/receive data across thread boundaries in ways that don't comply with the STA restrictions. Knowing beforehand what the apartment model of a given thread allows the IDE to catch these exceptions at compile-time instead of getting nasty access violation errors when you attempt to use an object across thread boundaries during runtime.

You can read about STA and MTA threads from the MSDN article at: http://msdn.microsoft.com/en-us/library/ms680112(VS.85).aspx

Note that even normal .NET applications (from before WPF) required the [STAThread] declaration atop of the main().

Is STAThread attribute a requirement or recommendation?

The [STAThread] attribute only works on the Main() entrypoint of a standalone executable program. It is a promise you make to the operating system, telling it that the main thread of your program is "well-behaved". It must pump a message loop and never block. Breaking the promise causes hard to diagnose misbehavior, deadlock is common.

None of this applies when you write an AutoCAD extension. You did not create the thread, AutoCAD did. You can't make any promises, it is AutoCAD that has to implement them. Nor is it a "main thread", that's a term that can only apply to a standalone program.

The thread that calls your extension is almost certainly already a single-threaded apartment, you can use Thread.GetApartmentState() in your code to double-check. STA is a requirement for a thread that displays UI, something that you very commonly do in an extension.

How do I test performance impact of [STAThread] in WinForms?

[STAThread] has too much mystique attached. But in practice is very simple, you make a promise. Cross your heart, hope to die. You promise to the OS that your main thread is a hospitable home for code that is not thread-safe. Keeping the promise requires having a dispatcher (Application.Run) and never blocking the thread. Things you do later, that's why you have to make the promise up front.

In a GUI app that runs on Windows there is always a lot of that code around. Whatever framework you use is the more obvious place for such code. But the far nastier stuff is the code you cannot see. The kind that lives inside shell extensions, in UI Automation code, in apps that want to provide data through the clipboard or drag+drop, in hooks installed with SetWindowsHookEx, in screen-readers for users with visual impairments, in ActiveX components that expect PostMessage to work. Such code doesn't have to be thread-safe, the OS does not demand that it is, mostly because whomever wrote that code has no way to test it. He didn't know beans about your app.

It matters to the OS because it has to do something when such code does not run on the UI thread. Since the code explicitly announces that it is not thread-safe, or doesn't have to be, it has to keep the code safe anyway. Only way that is possible is by initializing the code and make any future calls to it on the same thread. That requires some trickery, the code has to be marshalled, made to run on another thread, having a dispatcher loop is crucial to make that work. A dispatcher is the universal solution to the producer-consumer problem.

But if the code is initialized from the right thread then this is not necessary. How does the OS know whether it is the "right thread"? The [STAThread] promise tells it that.

So first conclusion you can make is not marking the UI thread as STA actually makes your program slower. Since every call is marshalled. Not the only problem, there is a lot of such code that cannot be marshalled. The author has to do extra work to enable it, he has to provide a proxy/stub. Sometimes it is just too hard, often he simply doesn't since he relies on you doing it right. So the call will fail miserably. But this happens in external code, you won't find out. So stuff just doesn't work. Or deadlocks. Or an expected event doesn't get raised. Miserable stuff. You must use [STAThread] to avoid the misery.

This is otherwise a pure Windows implementation detail, it does not exist on the Unixes. They have just completely different ways to provide these features, if at all. So [STAThread] does not mean anything on such an OS and testing what happens without it doesn't tell you anything.



Related Topics



Leave a reply



Submit