C# Multithreading and WPF Page Control - c#

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.

Related

Legacy code performance issue - Create UIControl on second thread, not only alter it

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.

Multi-thread debugging with VisualStudio and WebBrowser Windows.Forms controls

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.

How can I run UI on a thread other than the Main UI thread in .net?

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.

Is there an alternative to use the Background Worker in WPF?

I am a beginner with WPF, in my application I need to perform a series of Initialization steps, these take 10-15 seconds to complete during which my UI becomes unresponsive.
I was using yesterday the background worker but it didn't update my window, in fact it was frozen. Not sure, but maybe it didn't work because this control is only for Windows Forms.
UPDATE:
If not too much trouble, can you post me an example to use the alternative? For my case, the program will get some values from a database in a blucle.
Dispatcher.
The Dispatcher maintains a prioritized queue of work items for a specific thread. This might help you for updating your UI. If you have a lot of UI related initializations even this won't be able to help you much.
Dispatcher is not always an alternative to BackgroundWorker actually. The best practice is to select the more appropriate one as per your requirement. For example if you want something to execute without queuing BackgroundWorker is the solution. On the other hand if queuing is not a problem then Dispatcher is an alternative. For example, Dispatcher is using in Spell checkers and syntax highlighting functionality.
WPF Thread Model
All WPF applications start out with two important threads, one for
rendering and one for managing the user interface. The rendering
thread is a hidden thread that runs in the background, so the only
thread that you ordinarily deal with is the UI thread. WPF requires
that most of its objects be tied to the UI thread. This is known as
thread affinity, meaning you can only use a WPF object on the thread
on which it was created. Using it on other threads will cause a
runtime exception to be thrown. Note that the WPF threading model
interoperates well with Win32®-based APIs. This means that WPF can
host or be hosted by any HWND-based API (Windows Forms, Visual Basic®,
MFC, or even Win32).
The thread affinity is handled by the Dispatcher
class, a prioritized message loop for WPF applications. Typically your
WPF projects have a single Dispatcher object (and therefore a single
UI thread) that all user interface work is channeled through.
NOTE :
The main difference between the Dispatcher and other threading methods
is that the Dispatcher is not actually multi-threaded. The Dispatcher
governs the controls, which need a single thread to function properly;
the BeginInvoke method of the Dispatcher queues events for later
execution (depending on priority etc.), but still on the same thread.
See this thread for more information.
You could also queue items up with the thread pool and run the tasks like that, but be careful, if your tasks need to update the UI when they are finished you will have to marshal the data back to the UI thread.
One could use asynchronous delegates.
http://msdn.microsoft.com/en-us/library/ms228963.aspx
Just make sure if you are doing any UI related updates use:
Dispatcher.CheckAccess()
Here a simple example:
private void HandleUIButtons()
{
if (!btnSplit.Dispatcher.CheckAccess())
{
//if here - we are on a different non-UI thread
btnSplit.Dispatcher.BeginInvoke(new Action(HandleUIButtons));
}
else
{
btnSplit.IsEnabled = true; //this is ultimately run on the UI-thread
}
}
Taken from here:
http://blog.clauskonrad.net/2009/03/wpf-invokerequired-dispatchercheckacces.html

Multithreading on Windows Forms

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.

Categories