Here's a simplified example of what I'm trying to do:
I have 2 controls MyControl c and Panel p. p is created in the main GUI thread as normal, but I want c to be created in a background thread, because it takes awhile and I don't want to freeze the GUI. How can I add c to p.Controls? If I do it in this.Invoke it throws an exception for c, and if I do it from the background thread it throws an exception for p.
Or is it that I really shouldn't be creating GUI elements outside of the main GUI thread?
Or is it that I really shouldn't be creating GUI elements outside of the main GUI thread?
Yes, this is basically the problem. Most controls have thread affinity, and must be created within the user interface thread.
Typically, the way to handle this is to move the "work" that is causing the control creation to be slow onto a background thread, but still create the control on the UI thread. You'd then use Control.Invoke or Control.BeginInvoke to update the information in the UI once the slow work was completed.
For example, if you're loading a set of data from some external source, you can create the control, and start a background thread to load the data. Once the data is loaded, you can then update the control to reflect it. This will cause it to stay responsive the entire time.
It may be that your control does not take a long time to create; rather it takes a long time to get its data. In that case, consider creating a control that can display it UI while it is being populated. Then you can create the control in your main thread, populate it in a background thread, and give your users a better experience.
Use background thread to do what it has to do, and then signal somehow (bool _backgroundCompleted as a trivial example) that c is ready to be created.
Create c from Timer that will fire periodically and do nothing until _backgroundCompleted is set, then create c, then kill the timer.
It might be 'ugly', but it will work and will remain simple.
Forms.Timer, if you are asking ;)
And yeah, NEVER ever mess with multiple threads on the same form. You can have several forms on several threads, but to do that, you have to first RUN a new thread, then create a form ON it. It will have its own message loop, and will do fine.
Related
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 have a problem and after three days I still can not find a answer.
I am creating a usercontrol. This control has two controls hosted on it. One is an edit field and the other is a margin that will hold line numbers and other user added stuff.
What I am trying to do is instantiate these to separate controls in their own threads and perform all tasks on these threads eg painting and updating. The usercontrol thread will simply filter messages and direct same to the correct control. I will be doing this by overriding the WndProc method.
Doing all the message stuff I am fine with however how do I instantiate the controls. Once the thread that creates these controls finishes wont the threads die and the controls became inaccessible. Sorry no code at the moment, I tend to do a lot of research before any coding but I can't seem to find anything that can be of help.
This is not going to work very well. All UI elements (forms, controls, etc.) have thread affinity requirements that dictate that they can only ever be accessed from the thread that created them. Trying to embed a control hosted on one thread in another control from another thread is an effort in futility. Even if you can get it work (and use the term "work" loosely here) the results may be unpredictable at best. You need to rethink your approach. It would be much better to host all of the controls on the same thread and then shuttle off any time consuming operations to a worker thread. Remember, keep the worker thread busy with non-UI related operations only. Once the operation is complete then you can marshal over the results to the UI thread where it can dispatched appropriately to the controls.
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 am a bit confused about how GUI can be used in multi-threaded applications.
I hear there is a thing called the UI thread. Which I assume is my main executing thread at the startup of the application.
I also hear (though I am not 100% on this) that doing UI stuff on other (non UI) threads is a very bad idea.
So, if I create a separate thread and I want to call MyForm myForm = new MyForm(); myForm.ShowDialog(); in it, what changes do I need to make for that to be "safe"?
Also, I have had some people tell me that events are spun out on a different thread. (Though I am not sure I believe this.) If they are, then I am confused. I can open a dialog (ie myForm.ShowDialog() in an event and nothing truly horrible happens. (Maybe this depends on if the event delegate was called with Invoke or BeginInvoke?)
Here are a few bits of info that may help you out. What you're saying about working with UI on non UI threads isn't just a bad idea, you'll get an exception. Meaning, if you create a Form in the main thread, and then spawn off a background thread to do some processing and then want to update the Form in that background thread, it'll throw an exception. In your example though, where you create the Form in a background thread, you should be OK. I'd question your design, but it won't blow up AS LONG AS YOU ONLY TOUCH THE UI IN THAT SAME THREAD.
As for events, events handlers are executed on the same thread they were raised on. Meaning, if you have a Form on one thread that spawns off some work on another thread that raises events, but before doing so, you hook into this event on the Form thread, you need to be careful not to touch the UI directly in the event handlers, because those event handlers are being called on the background thread.
Finally, the way to correctly manipulate the UI from a background thread, is by calling Invoke and passing in a delegate that does the UI work you want. HTH
In WinForms you need to call UI-things on UI thread, you always can check on what thread you currents are getting InvokeRequired of UI-control.
void ApplyUiChanges()
{
if(this.InvokeRequired)
{
this.Invoke(new Action(ApplyUiChanges));
return;
}
// UI stuff here...
}
In WPF techinic is alike. But instead of using InvokeRequired you should ask CheckAccess() of DispatcherObject (All UI-controls derive from it)
void ApplyUiChanges()
{
if (!dispatcherObject.CheckAccess())
{
dispatcherObject.Dispatcher.Invoke(DispatcherPriority.Send, new Action(ApplyUiChanges));
return;
}
// UI stuff here...
}
Also you can take a look at Async CTP, which might be useful. But it's only CTP, not a release yet.
Another way to handle UI-thread communication is to use PostSharp. Write (or copy-paste) GuiThreadAttribute. After that, you'll be able to use such semantics:
[GuiThread]
void ApplyUiChanges()
{
// UI stuff here...
}
From what I've experienced, "UI thread" is a misnomer. There isn't one single thread that handles all of the UI for an application. To keep things simple, it's generally a good idea to have UI on one thread, but nothing stops you from spawning another thread, and creating new controls on that thread and showing them to the user. What's important is that control properties are only changed on the thread it was created on. As mentioned by another person, you can see if you are currently on that thread by looking at the Control.InvokeRequired property.
If you are on a thread that isn't the one you want a new form to run on and you don't have the luxury of being on the context of a control that is created on the thread you want, then you'll have to get a reference to the System.Threading.SynchronizationContext of the thread you want it to be on (I usually achieve this by storing a reference of System.Threading.SynchronizationContext.Current from the main thread in a static variable, but this can only be done after at least one control has been created on the thread). This object will allow you to run a delegate on its home thread.
I had to do this once in a Windows application that also hosted a WCF service, and UI needed to be launched from the service, but I wanted it on the same thread as the rest of the UI.
HTH,
Brian
In WinForms applications there is only a single thread which is the UI thread. You don't want to block this thread with long operations so that the UI is always responsive. Also you shouldn't update any UI elements from any thread other than the UI thread.
I always use a BackgroundWorker if I want to perform any lengthy operations from the UI. The major benefit of BackgroundWorker is that it can report progress and report that it is complete via ProgressChanged and RunWorkerCompleted. These 2 events occur in the UI thread thus you can update any UI element safely without the need to use InvokeRequired and Invoke.
I want to paralelize a 3D voxel editor built on top of Windows Forms, it uses a raycaster to render so dividing the screen and getting each thread on a pool to render a part of it should be trivial.
The problem arises in that Windows Forms' thread must run as STA - I can get other threads to start and do the work but blocking the main thread while waiting for them to finish causes strange random deadlocks as expected.
Keeping the main thread unblocked would also be a problem - if, for example, the user uses a floodfill tool the input would be processed during the rendering process which would cause "in-between" images (an object partially colored, for example). Copying the entire image before every frame isn't doable either because the volumes are big enough to offset any performance gain if it has to be copied every frame.
I want to know if there is any workaround to get the amin thread to appear blocked to the user in a way that it will not be actually blocked but will delay the processing of input till the next frame.
If it isn't possible, is there a better design for dealing with this?
EDIT: Reading the anwsers I think I wasn't clear that the raycaster runs in real time, so showing progress dialogs won't work at all. Unfortunately the FPS is low enough (5-40 depending on various factors) for the input between frames to produce unwanted results.
I have already tried to implement it blocking the UI thread and using some threads of a ThreadPool to process and it works fine except for this problem with STA.
This is a common problem. With windows forms you can have only one UI thread. Don't run your algorithm on the UI thread because then the UI will appear frozen.
I recommend running your algorithm and waiting for it to finish before updating the UI. A class called BackgroundWorker comes pre-built to do just this very thing.
Edit:
Another fact about the UI thread is that it handles all of the mouse and keyboard events, along with system messages that are sent to the window. (Winforms is really just Win32 surrounded by a nice API.) You cannot have a stable application if the UI thread is saturated.
On the other hand, if you start several other threads and try to draw directly on the screen with them, you may have two problems:
You're not supposed to draw on the UI with any thread but the UI thread. Windows controls are not thread safe.
If you have a lot of threads, context switching between them may kill your performance.
Note that you (and I) shouldn't claim a performance problem until it has been measured. You could try drawing a frame in memory and swapping it in at an appropriate time. Its called double-buffering and is very common in Win32 drawing code to avoid screen flicker.
I honestly don't know if this is feasible with your target frame rate, or if you should consider a more graphics-centered library like OpenGL.
Am I missing something or can you just set your render control (and any other controls that generate input events) to disabled while you're rendering a frame? That will prevent unwanted inputs.
If you still want to accept events while you're rendering but don't want to apply them until the next frame, you should leave your controls enabled and post the detail of the event to an input queue. That queue should then be processed at the start of every frame.
This has the affect that the user can still click buttons and interact with the UI (the GUI thread does not block) and those events are not visible to the renderer until the start of the next frame. At 5 FPS, the user should see their events are processed within 400ms worst case (2 frames), which isn't quite fast enough, but better than threading deadlocks.
Perhaps something like this:
Public InputQueue<InputEvent> = new Queue<InputEvent>();
// An input event handler.
private void btnDoSomething_Click(object sender, EventArgs e)
{
lock(InputQueue)
{
InputQueue.Enqueue(new DoSomethingInputEvent());
}
}
// Your render method (executing in a background thread).
private void RenderNextFrame()
{
Queue<InputEvent> inputEvents = new Queue<InputEvent>();
lock(InputQueue)
{
inputEvents.Enqueue(InputQueue.Dequeue());
}
// Process your input events from the local inputEvents queue.
....
// Now do your render based on those events.
....
}
Oh, and do your rendering on a background thread. Your UI thread is precious, it should only do the most trivial work. Matt Brundell's suggestion of BackgroundWorker has lots of merit. If it doesn't do what you want, the ThreadPool is also useful (and simpler). More powerful (and complex) alternatives are the CCR or the Task Parallel Library.
Show a modal "Please Wait" dialog using ShowDialog, then close it once your rendering is finished.
This will prevent the user from interacting with the form while still allowing you to Invoke to the UI thread (which is presumably your problem).
If you don't want all the features offered by the BackgroundWorker you can simply use the ThreadPool.QueueUserWorkItem to add something to the thread pool and use a background thread. It would be easy to show some kind of progress while the background thread was performing it's operations as you can provide a delegate callback to notify you whenever a particular background thread is done. Take a look at ThreadPool.QueueUserWorkItem Method (WaitCallback, Object) to see what I'm referring you to. If you need something more complex you could always use the APM async method to perform your operations as well.
Either way I hope this helps.
EDIT:
Notify user somehow that changes are being made to the UI.
On a(many) background threads using the ThreadPool perform the ops you need to perform to the UI.
For each operation keep a reference to the state for the operation so that you know when it completed in the WaitCallback. Maybe put them in some type of hash / collection to keep ref to them.
Whenever an operation completes remove it from the collection that contains a ref to the ops that were performed.
Once all operations have completed (hash / collection) has no more references in it render the UI with the changes applied. Or possibly incrementally update the UI
I'm thinking that if you are making so many updates to the UI while you are performing your operations that is what is causing your problems. That's also why I recommended the use of SuspendLayout, PerformLayout as you may have been performing so many updates to the UI the main thread was getting overwhelmed.
I am no expert on threading though, just trying to think it through myself. Hope this helps.
Copying the entire image before every frame isn't doable either because the volumes are big enough to offset any performance gain if it has to be copied every frame.
Then don't copy the off-screen buffer on every frame.