How will STAThread affect my multi-threaded program - c#

I've recently encountered a STA-related error in my program when I tried to launch an OpenFileDialog in a WinForm. I've done some reading, and before I add the [STAThread] attribute to my main thread I want to know how it will affect my program's execution.
I am a foreigner to COM so not everything I read made sense to me. Some points that stuck with me are:
The [STAThread] attribute defines the application as using a single-threaded apartment model.
More specifically, it changes the state of the application thread to be single-threaded.
http://www.a2zdotnet.com/View.aspx?Id=93
The STA architecture can impose significant performance penalties when an object is accessed by many threads. Each thread's access to the object is serialized and so each thread must wait in line for its turn to have a go with the object.
http://www.codeproject.com/Articles/9190/Understanding-The-COM-Single-Threaded-Apartment-Pa
I understand the need for thread-safety but I still don't understand what STAThread does. In my program (which I inherited from another developer) the main thread launches several other threads, one of which initializes the UI forms - and I think this is where the problem arises. With [STAThread] added what happens to the new threads? Does this affect multi-thread communication for non-Windows objects?
The error occurs when I try to open an OpenFileDialog in one of my forms. I added the dialog to the form using the VS designer: it didn't work. I then attempted to create a dialog box in a global file which is run by the main thread and call that instance from my form. It had no effect.

[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:
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.
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.

Related

C#.NET: "Multi Threaded Apartment" and "Multithreading"

I am learning multi threading concepts (in general and targeted to C#.NET). Reading different articles, still could not fully understand few basic concepts.
I post this question. "Hans Passant" explained it well but I was not able to understand some of its part. So I started googling.
I read this question which have no answers.
Is Multithreading and MTA same?
Suppose I write a WinForm application which is STA (as mentioned above its Main() method), still I can create multiple threads in my application. I can safely say my application is "multi-threaded". Does that also mean my application is MTA?
While talking about STA/MTA, most of the articles (like this) talk about COM/DCOM/Automation/ActiveX. Does that mean DotNet have nothing to do with STA/MTA?
No. MTA is a property of a single thread, just like STA. You now make the exact opposite promise, you declare that the thread does absolutely nothing to keep external code thread-safe. So no need to have a dispatcher and you can block as much and as long as you like.
This has consequences of course and they can be quite unpleasant. It is deadly if the UI thread of your program is in the MTA since it uses so many external components that are fundamentally thread-unsafe. The clipboard won't work, drag+drop doesn't work, OpenFileDialog typically just hangs your program, WebBrowser won't fire its events.
Some components check for this and raise an exception but this check isn't consistently implemented. WPF is notable, while apartment state normally matters only to unmanaged code, WPF borrowed the concept and raises "The calling thread must be STA, because many UI components require this." Which is a bit misleading, what it really means is that the thread must have a dispatcher to allow its controls to work. But otherwise consistent with the STA promise.
It can work when the component uses COM and the author has provided a proxy. The COM infrastructure now steps in to make the component thread-safe, it creates a new thread that is STA to give it a safe home. And every method call is automatically marshaled so it runs on that thread, thus providing thread-safety. The exact equivalent of Dispatcher.Invoke() but done entirely automatic. The consequence however is that this is slow, a simple property access that normally takes a few nanoseconds can now take multiple microseconds.
You'd be lucky if the component supports MTA as well as STA. This is not common, only somebody like Microsoft goes the extra thousand miles to keep their libraries thread-safe.
I should perhaps emphasize that the concepts of apartments is entirely missing in the .NET Framework. Other than the basics of stating the apartment type, necessary since .NET programs often need to interop with unmanaged code. So writing a Winforms app with worker threads is just fine, and those worker threads are always in the MTA, you do however get to deal with thread-safety yourself and nothing is automatic.
This is generally well-understood, just about everybody knows how to use the lock keyword, the Task and BackgroundWorker classes and knows that the Control.Begin/Invoke() method is required to update UI from a worker thread. With an InvalidOperationException to remind you when you get it wrong. Leaving it up to the programmer instead of the system taking care of thread-safety does make it harder to use threads. But gives you lots of opportunities to do it better than the system can. Which was necessary, this system-provided thread-safety got a serious black eye when Java punched it in the face during the middleware wars of the late 90s.
There are some questions but first let's start by this:
An Apartment is a context where a COM object is initialized and executed, and it can be a either single thread (STA), normally used for not thread-safe objects, or multi thread.
the term apartment, which describes the constructs in which COM
objects are created
From: https://msdn.microsoft.com/en-us/library/ms809971.aspx
So Multithreading and MTA are not the same, but MTA is Multithreaded.
We can say that STA and MTA are related to COM objects.
You can read more here: https://msdn.microsoft.com/en-us/library/ms693344(v=vs.85).aspx
So, for your second question, if your WinForm application is "multi-threaded" does not mean it is "MTA".
Finally, the MTA/STA concepts are older than .Net technology, but we cannot say that they have nothing related to, because .Net supports COM technology in both STA and MTA.
I expect my answer help you to undestand the difference between Apartment and Threading.
More interesting reading here:Could you explain STA and MTA?

Switching between STAThread and MTAThread and memory leaks

While looking for a memoryleak in a vb.net WebService, I detected that finalizers where blocked, and so several objects where never released (e.g. System.Threading.ReaderWriterLock)
Google told me that this might be, because the STAThread Attribute is set on my main method.
It took a long while until I found out that VB.net uses STA-as default, while c# uses MTA.
When I added the MTAThread-Attribute to my Main Method, everything worked fine and objects are released.
So if I understand it right, the Finalizer-Thread is blocked in STA-Mode.
So far so good, but to be honest, I heard about STA and MTA today for the first time.
Can I switch between STA and MTA without any thoughts?
UPDATE
I'm still not sure if I can switch between MTA and STA without breaking my code.
Here are some more thoughts
I do not use COM Objects in my code.
But some other libraries I'm using seem to use them under the hood, for example OracleCommand
My application is written in vb.net, and so by chance it is set to STA-Appartment, since this is the vb.net default, which I did not know at development time
If I wrote my application in c#, it would be set to MTA by default
So do I need to care about the COM Objects that are used under the hood or not?
because the STAThread Attribute is set on my main method
Yes, that's a regrettable practice that VB.NET inherited from VB6. A strong goal in COM (the original underpinning of VB6 and what you use in your web service) was to hide the complexities of threading and dealing with thread-unsafe code automatically without the client programmer having to know anything about it. A COM object tells the COM runtime what kind of threading it supports. By far the most common choice is "Apartment", a confuzzling word that means that it is not thread-safe.
COM solves thread-safety issues by automatically marshaling a call of the COM method from a worker thread to the thread on which the COM object was created. Thus guaranteeing thread-safety for the COM object. The equivalent in .NET is Dispatcher.Invoke() or Control.Invoke(). Methods that you have to call explicitly in a .NET program to keep the thread-unsafe user interface working, it is done entirely automagically for a COM object.
That kind of marshaling is pretty expensive, it inevitably involves two thread context switches plus the overhead of serializing the method arguments, tens of thousands of CPU cycles at a minimum.
A thread can tell COM that it is a friendly home for a thread-unsafe COM object and will take care of the marshaling requirements, it marks itself as a Single Threaded Apartment. STA. Any calls it makes to a COM method do not have to be marshaled and run at full speed. If a call is made from a worker thread then the STA thread takes care of actually making the call.
An STA thread however has to abide by two very important rules. Breaking one of those rules causes very hard to diagnose runtime failure. Deadlock will occur if you break those rule, like you observed for your finalizer thread. They are:
An STA thread must pump a message loop. The equivalent of Application.Run() in a .NET program. It is the message loop that implements the universal solution to the producer-consumer problem. Required to be able to marshal a call from one thread to a specific other thread. If it doesn't pump then the call made on a worker thread cannot complete and will deadlock.
An STA thread is not allowed to block. Blocking greatly increases the odds for deadlock, a blocked thread isn't pumping messages. The lesser problem in a .NET program, the CLR has a great deal of support for pumping itself on calls like WaitHandle.WaitOne() and Thread.Join().
Sometimes the COM component itself will make hard assumptions about being owned by an STA thread. And use PostMessage() internally, usually to raise events. So even though you never actually make any calls on a worker thread, the component will still malfunction. WebBrowser is the most notorious example of that, its DocumentCompleted event won't fire when the thread doesn't pump.
Your web service no doubt violated the first bullet. You only get a message loop automatically in a Winforms or WPF application. And yes, poison to the finalizer thread since its final release call on the COM object must be marshaled to keep the object thread-safe. Deadlock is the inevitable outcome since the STA thread isn't pumping. A ratty problem that's pretty hard to diagnose, the only hint you get is that the program's memory usage explodes.
By marking the thread as MTA, you explicitly promise to not provide a safe home for an apartment-threaded COM server. COM is now forced to deal with the hard case, it must create a thread by itself to provide safety. That thread always pumps. While that can solve the problem with your web server, it should be noted that this is not a panacea. Those extra threads do not come for free and the calls are always marshaled so always slow. Getting too many of those helper threads is a ratty problem that's pretty hard to diagnose, the only hint you get is that the program's memory usage explodes :)
Automatic thread-safety is a very nice feature. It works 99% of the time without any hassles. Getting rid of the 1% failure mode is however a very major headache. Ultimately it boils down to the universal truth, threading is complicated and error prone. One approach is to not leave it up to COM but take the threading bull by the horns yourself. The code in this post could be helpful with that.

onuserpreferencechanged hang - dealing with multiple forms and mutlipe ui threads

I think my problem is similar to:
.NET 4.0 and the dreaded OnUserPreferenceChanged Hang
I have also looked through:
http://ikriv.com/en/prog/info/dotnet/MysteriousHang.html#BeginInvokeDance
I have removed our splash screen.
I also tried adding the suggested code: Microsoft.Win32.SystemEvents.UserPreferenceChanged += delegate { }; to our main() method.
I'm looking for some ideas and information on how to troubleshoot.
For our main() method we start a windowmanager class which is a form using Application.Run
It is just an icon in the task tray ( we don't show a window).
Whenever we launch an object we have a background thread which creates a form and then does Application.Run( form )
At the time of Application.Run( form ) form.IsHandleCreated = false.
I use the freezer application from the MysteriousHang website. (I modified it to keep sending the change notification in a loop ).
How should I be handling creating and running the new form? Does it matter that the form is created on the background thread even if its handle isn't created yet?
I'm also confused about the terminology "UI thread".
A UI thread is a thread that pumps a message loop. And operates in a mode that's compatible with user interface objects, it needs to be an STA, a Single Threaded Apartment. That's a COM implementation detail that matters a great deal to common UI operations that are not thread-safe and require an STA, like Drag+Drop, the Clipboard, shell dialogs like OpenFileDialog and ActiveX components.
It is the CLR's job to call CoInitializeEx() and select the apartment type. It does so guided by the [STAThread] attribute on the Main() entrypoint in your program. Present in projects that create UI objects like a Winforms or WPF app. But not a console mode app or service. For a worker thread, in other words a thread that was created by your code instead of Windows, the apartment type is selected by what you passed to Thread.SetApartmentState() method. The default is MTA, the wrong flavor. A threadpool thread is always MTA, that cannot be changed.
The SystemEvents class has the unenviable task of figuring out which thread is the UI thread in your program. Important so it can raise events on the correct thread. It does so by using a heuristic, the first thread that subscribes an event and is an STA thread is considered suitable.
Things go wrong when that guess wasn't accurate. Or certainly in your case where you try to create multiple threads that create UI objects, the guess can only ever be correct for one of them. You probably also forgot to call Thread.SetApartmentState() so it won't be correct for any of them. WPF more strongly asserts this and will generate an exception when the thread isn't STA.
The UserPreferenceChanged event is a trouble-maker, it is subscribed by some of the controls you find on the toolbox. They use it to know that the active visual style theme was changed so they'll repaint themselves, using the new theme colors. A significant flaw in the event handlers in some of these controls is that they assume that the event is raised on the correct thread, the same thread that created the control object.
This will not be the case in your program. The outcome tends to be unpleasant, subtle painting problems are a minor flaw, deadlock is certainly possible. For some reason, locking the work station with Windows+L and unlocking it is particularly prone to causing deadlock. The UserPreferenceChanged event is raised in that case because of the desktop switch from the secure desktop the user's desktop.
The controls that listen to the UserPreferenceChanged event and do not use safe threading practices (using Control.BeginInvoke) are DataGridView, NumericUpDown, DomainUpDown, ToolStrip+MenuStrip and the ToolStripItem derived classes, possibly RichTextBox and ProgressBar (unclear).
The message ought to be clear, you are using unsafe threading practices and they can byte. There in general is never any point to creating UI on a worker thread, the main thread of a Winforms or WPF program is already quite capable of supporting multiple windows. Short from avoiding the dangerous controls, this is what you should strive for to get rid of the problem.

C# - When to Make Thread-Safe Calls

I have a large project that I'm working on in C#, a language I'm fairly new to. The project heavily relies on a GUI and there is a lot of data that is displayed. Recently, we've been getting cross-threading errors in places that they never were before. These errors where they occurred were easily solved:
if (logListView.InvokeRequired)
{
logListView.BeginInvoke(new MethodInvoker(
() => logListView.Items[logListView.Items.Count - 1].EnsureVisible()));
}
else
{
logListView.Items[logListView.Items.Count - 1].EnsureVisible();
}
My question however, is this: Does that method need to be applied EVERY TIME I access a Windows Form object? Are there special cases? I'm not using multi-threading, so to the best of my knowledge where these errors occur are out of my control. E.g. I can't control which piece of code is executed by which thread: C# is doing all of that on it's own (something I don't really understand about the language). Implementing an if statement for each line that modifies the GUI seems exceptionally obnoxious.
You only need that code if you access winform components from outside the UI thread (ie. from any thread you have spawned). There are some components in the core library that spawn threads, for example the FileSystemWatcher. Winforms doesn't just spawn threads on its own, it only has the UI thread. Any cross-thread issues occur because of code you wrote or libraries you use.
You only need to invoke the code when the code is not running in the GUI thread.
I can't control which piece of code is executed by which thread
Yes, you can. There is nothing unpredictable about which code runs in the GUI thread, you just have to find out what the rules are.
The only code to run out of the GUI thread in your code would be methods that runs as an asynchronous callback, for example a timer or an asynchronous web request. (The System.Windows.Forms.Timer runs the Tick event in the GUI thread though.)
(There are other ways of running code in another thread, but then you would be aware of using multi-threading.)

Are there any problems with having a group of win forms in one thread and another group in another thread?

I have an application that has two distinct groups of win forms and I want each group to operate in separate threads. Are there any problems with this approach as long as I BeginInvoke/Invoke when operations happen across the different threads?
This question stems from the fact that I've always been used to thinking in terms of a 'gui thread' that I must if (InvokeRequired) { Invoke } else { ... } and all forms live on that thread.
An alternative angle on this question:
Is there anything 'special' about the default thread that win forms exist in or is it the same as any other thread?
Well, there are ways to shoot the foot but Windows Forms rarely forgets to tell you about it.
Yes, there's something special about the "main thread". It runs in STA mode, a Single Threaded Apartment. It is a mode that affects COM components, the shell dialogs like OpenFileDialog and operations like Drag + Drop and the Clipboard. Threads that display a UI always must be STA. That's automatic in normal WF apps with the [STAThread] attribute on the Main() method. In your own app you have to call Thread.SetApartmentState() before you start it. And the thread is special because it pumps a message loop (Application.Run), a requirement for STA threads.
By default, any Thread you start or any threadpool thread runs in MTA mode. Threadpool threads cannot be changed, they are always MTA.
It should work just fine, I am pretty sure that in my current project it is implemented this way and we didn't see any issues with this. You just need to remember to use the correct control when you use InvokeRequired and Invoke methods.
A GUI thread simply pumps messages so that it can process the standard Windows messages, I don't think there is anything else special about it.
the only problem that I can think of is related to very very old COM components, that are related to the main single threading apartment.
msdn.microsoft.com
but this is very unlikely

Categories

Resources