Good morning,
I made a simple dll in which I use a WebBrowser control to do some simple tasks. Now I want to use its methods from the main UI in a separate Task or a BackgroundWorker. The problem is that whenever I use the methods I get the "no STAThread" exception... How can I get around this? Of course, in the dll there is no Main() method and I can't either add the STAThread attribute to the constructor.
Thank you very much.
Well, to get code running in a new STA thread you should create a new thread and explicitly force it to be an STAThread using Thread.SetApartmentState before starting it. You'll then need to use Control.BeginInvoke to marshal calls back to the UI thread - you don't want to use BackgroundWorker or Task, as those will use a threadpool thread.
On the other hand, it's not clear whether that will help in this case - if you're using a WebBrowserControl you'll probably need a message loop running etc.
It's not really clear what you mean by "use its methods from the main UI". Is this WebBrowserControl part of the UI which is running in the normal UI thread? If so, you'll need to marshal to that thread from the other thread (e.g. using Control.BeginInvoke) - and the other thread doesn't need to be an STA thread for that to happen.
Related
I'm building a WPF application. I'm doing some async communication with the server side, and I use event aggregation with Prism on the client. Both these things results in new threads to be spawned which are not the UI thread. If I attempt to do "WPF operations" on these callback and event handler threads the world will fall apart, which it now has started doing.
First I met problems trying to create some WPF objects in the callback from server. I was told that the thread needed to run in STA mode. Now I'm trying to update some UI data in a Prism event handler, and I'm told that:
The caller cannot access this thread because a different thread owns it.
So; what's the key to getting things right in WPF? I've read up on the WPF Dispatcher in this MSDN post. I'm starting to get it, but I'm no wizard yet.
Is the key to always use Dispatcher.Invoke when I need to run something which I'm not sure will be called on the UI thread?
Does it matter if it actually was called on the UI thread, and I do Dispatcher.Invoke anyway?
Dispatcher.Invoke = synchronously. Dispathcher.BeginInvoke = async?
Will Dispatcher.Invoke request the UI thread, and then stop to wait for it? Is it bad practice and risk of less responsive programs?
How do I get the dispatcher anyway? Will Dispatcher.CurrentDispatcher always give me the dispatcher representing the UI thread?
Will there exist more than one Dispatcher, or is "Dispatcher" basically the same as the UI thread for the application?
And what's the deal with the BackgroundWorker? When do I use this instead? I assume this is always async?
Will everything that runs on the UI thread (by being Invoked) be run in STA apartment mode? I.e. if I have something that requires to be run in STA mode - will Dispatcher.Invoke be sufficient?
Anyone wanna clearify things for me? Any related recommendations, etc? Thanks!
Going over each of your questions, one by one:
Not quite; you should only invoke onto the UI thread when necessary. See #2.
Yes, it does matter. You should not just automatically Invoke everything. The key is to only invoke onto the UI thread if necessary. To do this, you can use the Dispatcher.CheckAccess method.
That is correct.
Also correct, and yes, you do run the risk of less responsive programs. Most of the time, you are not going to be looking at a severe performance hit (we're talking about milliseconds for a context switch), but you should only Invoke if necessary. That being said, at some points it is unavoidable, so no, I would not say it is bad practice at all. It is just one solution to a problem that you will encounter every now and then.
In every case I have seen, I have made due with Dispatcher.CurrentDispatcher. For complex scenarios, this may not be sufficient, but I (personally) have not seen them.
Not entirely correct, but this line of thinking will not do any harm. Let me put it this way: the Dispatcher can be used to gain access to the UI thread for the application. But it is not in and of itself the UI thread.
BackgroundWorker is generally used when you have a time-consuming operation and want to maintain a responsive UI while running that operation in the background. Normally you do not use BackgroundWorker instead of Invoke, rather, you use BackgroundWorker in conjunction with Invoke. That is, if you need to update some UI object in your BackgroundWorker, you can Invoke onto the UI thread, perform the update, and then return to the original operation.
Yes. The UI thread of a WPF application, by definition, must be running in a single-threaded apartment.
There's a lot to be said about BackgroundWorker, I'm sure many questions are already devoted to it, so I won't go into too much depth. If you're curious, check out the MSDN page for BackgroundWorker class.
Sometimes I saw that when I call a method from my form to do something that my UI freezes. How to solve this problem? If I call that method in separate thread then problem will be solved?
If I call method in separate thread like the code below
new System.Threading.Thread(delegate()
{
HeavyMethod();
}).Start();
does this solve my problem or is there any better solution?
Call the method on a Background Worker would be the best solution.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
Doing that you can control when things get updated (using the Report Progress Feature) and allow you to cancel the work.
Also, make sure that whatever resources you manipulate in the backgroundWorker1.RunWorkerAsync(); are properly shared. You can get into what is called "Race Conditions" which causes your output to be non-determanistic (e.g. you won't get the same results every time you run the method)
For a good walk through on Multithreading and shared resources, see this link:
http://www.c-sharpcorner.com/uploadfile/mgold/multithreadingintro10062005000439am/multithreadingintro.aspx?articleid=920ecafc-e83b-4a9c-a64d-0b39ad885705
If you are calling your method in response to an event, then by default the method will be running on the GUI thread (the thread that the runtime uses to handle all user events). If that method is huge and/or heavy, then it will "freeze" the UI as you describe.
Making it run on a separate thread is a viable solution for many of these cases.
There are cases, however, when you'll actually want the UI to "block" (for example, if you are updating a lot of controls, you don't want the user to mess with them in the meanwhile). For such cases, the sanest approach is to pop up a modal "wait" dialog.
Since it is C# 2.0, I suppose it is WinForms. Don't hold up the UI thread with CPU-bound code.
You can spawn a new thread to run your CPU-bound code, but you have to be careful not to access WinForms controls, especially not to update control properties. Many WinForms controls can only be accessed/updated from the UI thread. Check the InvokeRequired field to see if you need to marshal (i.e. use Invoke) the call from another thread back to the UI thread.
Also consider using the ThreadPool instead of creating a new thread.
That is correct, If you move the heavy processing off of the UI Thread then it should free up the UI to redraw. For what you want to do your implementation should work just fine. Although ThreadPooling or BackgroundWorker would be the suggested implementations (http://msdn.microsoft.com/en-us/library/system.threading.threadpool(v=VS.80).aspx), (http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx).
I'm making several HttpWebRequest.BeginGetResponse calls, and in the callback method of the BeginGetResponse, I'm invoking an EventHandler. In the EventHandler, there is logic to test if the download was successful. If not, it tries to redownload the Html. I'm noticing lots of threads being generated especially when there are errors. So, on which thread do the Async Callbacks run?
Is there anyway I can invoke the EventHandler on the original thread? If that is not posible, can I invoke it on the UI thread?
Thanks!
Callbacks are made on a threadpool thread. There is no mechanism in .NET to make code run on a specific thread. That is very hard to come by, you can't just interrupt a thread while it is busy and make it run some code. That causes horrible re-entrancy problems that a lock cannot solve.
A thread must be in an idle state, not actively mutating the state of the program. There's one kind of thread that behaves that way, the UI thread in a Winforms or WPF app. That's also the thread that has to deal with objects that are fundamentally thread-unsafe, anything related to the UI. This is not a coincidence.
Both class libraries make it possible to marshal a call from a worker thread to the UI thread, specifically to help getting the UI updated in a thread-safe way. In Winforms you use Control.Begin/Invoke(), in WPF you use Dispatcher.Begin/Invoke(). BackgroundWorker is a handy class to get this done without explicitly managing the marshaling. But isn't suitable for I/O completion callbacks.
What do you mean by "on the original thread"? Which original thread? You can marshal to the UI thread using Control.BeginInvoke or Dispatcher.BeginInvoke. You can't marshal to an arbitrary thread - it has to have something like a message pump waiting for work.
As for which thread HttpWebRequest async callbacks are executed on - I would expect either a general thread pool worker thread, or possibly an IO completion port thread.
Using the Begin/End Async pattern, be aware that it's possible for many kinds of tasks to complete on the thread they were called from. When you call BeginXXX, it returns a boolean that signifies if the task was completed on the calling thread or not.
The basic answer is, it could be any thread.
If you are using WPF you can use the Dispatcher to invoke your logic on the UI thread.
Otherwise, (if not in WPF) you could use a SyncrhronizationContext to accomplish the same thing.
I'm creating a new thread and within the background thread method I do work and then call another method to do work.
myThread = new Thread(new ThreadStart(doWork));
myThread.Start();
The problem is that when I leave the background worker method to go to another method and execute this :
browser.SelectList(Find.ById("selStartYear")).SelectByValue(startYear);
I get an InvalidCastException.
When my background worker method is finished do I need to do something with the thread? I see that I started the thread, but calling abort on it in the new method it calls just suspends the program.
Edit: I'm using WakiN and created new IE in the global scope:
IE browser = new IE("http://www.website.com/");
My worker method references this as does the failing method.
No, you do not need to do any cleanup on a thread that has finished executing. You should actually strive never to call Abort, as that's a destructive method and providing a more "polite" means of signaling the thread that it should exit immediately is preferred to ending it violently with Abort.
Also, if your job is not particularly long-running, then you should probably be using either the new Task class available in System.Threading.Tasks or using System.Threading.ThreadPool.QueueUserWorkItem() instead of spinning up your own thread.
That being said, you aren't providing enough information to answer your InvalidCastException issue. What is the cast it's trying? What is the relation (if any) between the body of doWork and the values being used in your failing statement?
Adam provided a complete answer on threading issue. I just another hint. Your thread (as I see in sample code) is not a background thread. Also I think all multi-thread applications needs a plan for a graceful exit (consider a system shutdown).
To find out what's the source of casting error, I suggest breaking that line of code into 3 lines, since one of the parameters is not in the right type.
how can i make a user control to run on its own thread ?
e.g. by following code in a user control , coz user control uses main app thread it make main thread to sleep
Thread.Sleep(TimeSpan.FromMinutes(2));
User controls need to run on the UI thread because that is a restriction in the Windows API. If you try and use Windows Forms controls from another thread you will get an exception.
You can run other code in another thread, but use the UI thread to update the controls. You can use BackgroundWorker for this. Or you can use the InvokeRequired and Invoke or BeginInvoke methods on the control instance to have it execute code on the UI thread.
You mention you want to use a mutex lock. A mutex is to avoid having multiple threads access a resource at the same time. If all your code is running in the same thread then you don't need a lock at all.
Objects don't really "run" themselves - methods are executed on a thread.
Now if you want a particular method to execute in a different thread, you need to either create a new thread, use the threadpool explicitly, or use something which uses the threadpool for you - such as BackgroundWorker.
What are you doing when you want to sleep for two minutes? Could you avoid sleeping by just setting a timer to fire (in the UI thread) in two minutes instead? If this is part of some long-running process, you should use BackgroundWorker or some other way of executing on a different thread, but with the control itself still handling updates and events on the UI thread.