We're creating a few threads in a Windows.Forms solution.
We've also got a BrowserControl (yup, it's OAUTH) and of course I'm finding issues with debugging -
Cross-thread operation not valid: Control 'xxForm' accessed from a
thread other than the thread it was created on
And yet I am calling 'correctly'
xxForm.Show()
by ensuring it's wrapped in an invoke call
.Invoke(new MethodInvoker())
and still I get the thread issue. I can do everything else (Focus, BringToFront) it's the Show that errors.
Moreover, the GUI never gets the browser response and shows. In the VS debugger I get the above threading erropr (apartment state of background thread == MTA). When run as an EXE the same code has a threading aparement of STA and the GUI will never show when debugging, but if I run the EXE directly, there's no threading issue, the browser control just never responds to input.
Spo the questions are:
Why the different behjaviour in VS / EXE?
How do I debug in VS?
Does the BrowserControl play ok with multiple threads?
Update
YES I KNOW there's no code - it's too long. I'll see what I can do.
Also please read the question before posting an answer. I am invoking the background thread on the UI thread. That's not the issue. This has NO EFFECT on the result. I'll down vote answers that recommend that.
Also some hope - I've searched for many hours. It's linked the the message pump. Unless the message pump is running the DocumentCompleted event isn't received.
Update 2
Best I manage is pseudo code:
Program:
startWorkQueue
LoadForm (don't show)
Thread1:
addToQueue
Thread2:
readFromQueue
ShowForm (on occasion)
Now the ShowForm method is on a Windows.Form control.
Within this any call is made via an Invoke, so that despite the 2nd thread making the call the ShowForm, the actual .Show() etc etc calls are on the UI thread.
So what am I missing? I just don't understand why there's a cross thread exception....
Ok I've found out what was going on and I'll post here for reference.
I hope it helps someone in the future.
We had some different constraint to the vanilla Forms applications - our Forms were created on the Main thread but had Show() called on a different thread. We also don't have a starting UI - we sit in the background and sometimes react to events with UI prompts.
As such a number of issues hit us. Rather than list them all I'll detail our takeaways:
Application.Run
If decide NOT to Show a Form at the start of your application… then you'll need to consider threads carefully (see Form.Show notes)
Form.Show
This does all resource allocation etc, NOT the Load/ctor
Performs handle creation / resource allocation
Handle creation
Hwnd
If we attempt to access certain Form properties before it has Show(n) then you'll need to create a handle manually (or an Exception is created)
• As easy as if (!IsHandleCreated) { CreateHandle(); }
HOWEVER
This create the control/form
Therefore the control/form is created on the Thread that calls the Handle create
This must be the same UI thread (STA) as the Main function
• Otherwise much weirdness occurs
SO
You aren't restricted by what to do with Application.Run
You can access properties in .Show (but you may need to create a handle first)
You can call Show from a different thread, but ensure the handle is ONLY created on the main thread
I hope it helps, I can provide more details on our specific problems if need be.
Various aids that helped included displaying ManagedThread AND ProcessId in the log and scouring MSDN.
Since the code has not been pasted, I would like to remind you that in WinForms, the UI elements should be accessed only on the UI thread. Any other thread apart from UI thread should not be updating the UI elements directly.
Related
I am a beginner on C#. There is a project I am working on need to use 2 threads. The main one is for displaying the usual Wpf pages. Another one monitoring the inputs from hardware. If there is a desired input signal detected, the whole system should stop and shows a warning page on the window, which is controlled by the main thread.
Now I get stuck on how to do the deal with the threads when the input signal detected. Should I pass a signal to the main thread, and ask the main thread to display the warning page, and stop the secondary thread. Or I should let the secondary thread display the warning page directly, and take over the control priority from the main thread?
Or I should let the secondary thread display the warning page directly, and take over the control from the main thread?
That makes literally no sense at all.
Should I stop the secondary thread and pass a signal to the main thread, and ask the main thread to display the warning page.
That also makes no sense at all, but at least there's a gleam of sort of what you mean here. To be absolutely clear, there's no such thing as "stopping threads" as you mean.
But yes, you send a message to the GUI thread to update its state, specifically using Dispatcher.BeginInvoke in WPF.
WPF, like most GUI toolkits on Windows at least, has sticky controls - which essentially means they have thread affinity and cannot be accessed from other thread which didn't create them. [You can verify that from source, there are calls to VerifyAccess() littered all over the place.]
That design constraint rules out the possibility of other thread "taking over" anything from another thread, ever.
But the world doesn't end there, and cross-thread communication is common enough requirement that the designers have provided you with the means to satisfy the same thread requirements yet send messages across threads.
The way to do that lies with two members of Dispatcher object each WPF window has. You can read the full details here and on associated pages for that type, but roughly it goes like
protected void Button_Clicked(object sender, EventArgs args) =>
Dispatcher.Invoke(() => { /* Your method body which will be executed on the proper thread. */ });
If you prefer asynchronous communication, you can use either BeginInvoke or InvokeAsync instead.
I inherited a winforms app. It uses a third-part-closed control that renders documents and photos... It has only sync methods for opening a document. The problem is that my clients are dealing with really big documents (in the area of 2GB!!!) and opening these docs really "block" the UI thread... which is bad...
Common sense would make you think "Just off-load it to a background thread" but the question is "HOW"! See, to alter the control (because calling "Open" causes it to be altered) I need to Invoke it, and that causes the code to run o UI thread again... locking it up...
So I turned the table upside down. What if instead of creating the control on the main thread and passing it to a background thread for processing, I could create the control on the background thread, load it up (avoiding this way the cross-thread exception) and, when done, feed it to the main thread?!?
Right now what I need is to know how to definitively handle a control to another thread, and not only temporally...
I'm not sure if this is possible but you could try to:
create a new form on a secondary thread (this form will host your fancy control)
load the document from this secondary UI. It will be blocked but you can hide it and only display a
loading message on the main UI.
when the job is finished transfer the 'work' to main UI and main thread.
It's just an idea.
What you are asking to do is impossible. A Winforms control's thread affinity is determined when that control is created, and it cannot be changed.
The best solution is to not use that control. I doubt there's anything it does that cannot be implemented correctly and competently by someone else.
If you are okay running a completely different window in a second STA thread, then that would be the next best thing. That particular window will still be frozen while the document loads, but at least your main UI would still be okay. Note that you should not try to mix and match controls from different threads in the same window; that will lead to all kinds of headaches.
Finally, as a complete hack, you might consider going ahead and calling this Open() method in a background thread in spite of the control being owned by the main UI thread. On the admittedly shaky assumption that the only time that control will actually attempt to access the UI component itself would be at the very end of the Open() method operation, you can go ahead and catch the InvalidOperationException that is thrown, and use that as your signal that the document loading has completed. Then just invalidate the control in the main UI thread.
I'd give the odds of this last suggestion working no better than 50/50. It will depend on what the control actually does with the loaded data, and if it's some kind of composite control where it's relying on actually taking the result of its loading and copying that to a control as part of the Open() method, that part might fail and the control would not wind up properly initialized.
I know there are other questions around this but most end up with the answer don't do what I am about to suggest. So I know you aren't supposed to. The reason for this question is I want to do it anyway, how can I do it...
Here is why I want to break the rules...
Let's say I have a complicated application, it's version 1 and we want our customers to submit errors to us in the event of crashes or hangs. Let's now say I have a button on the top of the main form they click to submit reports.
Let's now imagine that the application hung because of a deadlock...
It would be nice if that small piece of UI and a handler for that button could live on a thread other than the main ui thread so that it isn't caught up in the deadlock. When clicked it would gather all the call stacks for the other threads and submit them to our error reporting service.
Now, knowing the scenario, can this be done in .net?
Yes, there is no magic in creating UI on another thread than the "main thread". The important rule to always keep in mind is to interact with that UI on the thread that created it.
Still, I feel that you are attacking this from the wrong angle. You should probably instead make an effort to push all work off the main thread. That way you minimize the risk for that thread to freeze, and then you don't need to resort to unorthodox solutions for the error reporting.
I have various cases of creating forms on non-main thread, and it works fine every time.
Create a new Thread, and show a Form from it. New message loop will be created for that thread and everything will run fine.
What magic will you use to gather data from the crashed app and locked main thread, that's up to you :)
if application hung, your main message loop is dead, thus ui will not work. As workaround for your problem i'd consider usage of external application (another exe) which will be invoked in case of report
in any case, if you want to invoke UI from other thread you should perform context switch In case of winforms, follow this answer
It sounds like you'd like to keep the UI alive, even when some other operation is mired in a deadlock. If so, perhaps Asynchronous Programming would be of use. Using Async to manage a potentially hung up task would allow the remainder of the application to remain responsive.
we want our customers to submit errors to us in the event of crashes or hangs
You might also consider adding some degree if instrumentation/reporting, so that you'll have this data without requiring user input.
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 have a c# .NET multi-threaded application that is freezing the interface. What is unusual about this is that the interface does not freeze unless I let the system sit idle long enough for the screen saver to start (which requires me to reenter my password to re-gain access to the system). When the interface becomes visible again (after I have successfully entered my password) the interface is locked up. As long as I don't let the screensaver start, then the interface does not lockup.
I should point out that I have two different executables that access the same dll and this problem is occurring no matter which application I use to access the DLL. This seems to imply that the problem is in the DLL as the two applications are completely different (C++/MFC) and (C#/.NET) apart from how they relate to the DLL.
Both exes perform similar steps in how they interact with the DLL. They make calls into the dll to setup the serial port communication, open a status window in the DLL, start a thread in the DLL to monitor the comm port, and then starts a thread in the main app that monitors a stack in the dll.
When data is obtained from the comm port by the thread in the DLL, it is parsed and its results are placed on the stack and then posted to the status window via a delegate. When the thread in the exe sees data in the stack, it outputs the data in the main window, also using a delegate.
I found that if I add code to the thread inside the DLL so it calls Application.DoEvents() every 30 seconds, the interface will be frozen for about 30 seconds and then resume activity like normal.
I figure something is blocking the main thread and forcing DoEvents() to fire seems to break the lock, but I have no idea what might be causing this lock.
This issue occurs both on my development machine and on a test machine.
I have tried completely removing the output of data to the status window inside the DLL, but that didn't make any difference.
I have been doing multi-threaded programming for years and never seen anything like this; so any advice would be greatly appreciated.
Thanks.
This is a problem that's commonly induced by the SystemEvents class when you have a non-standard way to initialize your user interface. Using threads, specifically. Start your program, Debug + Break All, Debug + Windows + Threads. If you see a thread named ".NET SystemEvents" then you're pretty much guaranteed to get this hang.
Some background: the SystemEvent class supports both console mode apps and GUI apps. For the latter, it should fire its event handlers on the UI thread. The very first time one of its events is subscribed, it creates a little invisible helper window to get the system notifications. It can do this two ways, either by creating the window on the calling thread or by starting up a helper thread. It makes the decision based on the value of Thread.GetApartmentState(). If it is STA then it can create the window on the calling thread and all event callbacks can be properly marshaled to that thread.
This goes wrong if the first window you create is not created on the UI thread. A splash screen for example. That window may contain controls that are interested in a system event like UserPreferenceChanged so they can properly repaint themselves. It now uses the helper thread and any event will be fired from that helper thread, not the UI thread. Poison to any window that runs on the UI thread. The session switch out of a locked workstation (including the screen saver) is for some mysterious reason very likely to cause deadlock. You may also see an occasional painting mishap, the less nasty result of using windows from the wrong thread.
Short from fixing the initialization order, a workaround is to put this in your Main() method, before any windows are created:
Microsoft.Win32.SystemEvents.UserPreferenceChanged += delegate { };
The problem does appear to be related to the ActiveX control is was probably using incorrectly in a form. I switched to using the serial port library in .NET and have not been able to reproduce my problem. Thanks to everyone, especially Hans for their assistance.
I am having the same issue as my PC just hangs up when the screen saver kicks off or I lock my PC and monitor goes to sleep.
I am 95% sure that there are deadlocks appearing in my multithreaded app. Look and identify whether there are any deadlocks in your code.