Skip windows messages when forcing execution of the Dispatcher queue - c#

I am currently forced to update some part of the UI while some lengthy operation is performed on the UI thread. I know this should not be done, but - as I said - I am forced...
I have therefore added the following call to the location where the UI should be updated:
Dispatcher.Invoke(() => { }, DispatcherPriority.Render);
As you may know, this will force the Dispatcher Queue to be processed until all queued delegates up to (and including) priority Render have been executed. This way, the UI is updated although the UI thread is currently blocked.
Now, my problem is: When calling the Invoke method, the dispatcher queue does not only contain the delegates for re-rendering the UI, but obviously it also contains some custom Windows message. This Windows message is generated by our own application and it will be executed during the Invoke call. However, I do not want this because it introduces weird side effects! I only want the UI to be redrawn.
Is there any way to force UI rendering without processing any other Windows messages?
I tried to achieve this by calling some Win API functions:
private static readonly uint MSG1 = 0xC21E;
private static readonly uint MSG2 = 0xC25D;
// ...
while (PeekMessage(out msg, IntPtr.Zero, MSG1, MSG2, (uint)PeekMessageParams.PM_REMOVE))
{
TranslateMessage(ref msg);
DispatchMessage(ref msg);
}
MSG1 and MSG2 are messages that I found when I inspected the messages in the queue while the UI is blocked and my UI updates are done. I assumed that these messages have something to do with re-rendering the UI, but that assumption is not correct obviously. At least, the UI is not refreshed with the above code.
Any other ideas?
EDIT:
I just found the Dispatcher.Yield() method which was introduced in .NET 4.5. The documentation says:
Use this method if want to give your app a chance to process events while your app is doing a lot of work on the UI thread. For example, you can use this method in a long-running loop that updates a control.
Does anybody have any experience with this method?

Related

Deadlock in WPF: How to not block the GUI thread in HwndHost.BuildWindowCore?

We have a large code base for processing and visualizing images in C++ with Qt. Now a user wants to build on that, but their code base is .NET Core 3.1 with WPF. We use PInvoke to interface the native code, and can very successfully join the projects. The few native widgets are embedded with Win32-in-WPF-HwndHost wrappers. Everything works pretty good and we're quite happy about the mileage we're getting!
There is just one blocker problem: The HwndHost method BuildWindowCore can sometimes hang in a deadlock. We could identify the root cause of the deadlock:
When BuildWindowCore calls into Qt to re-parent the native widget into the managed widget's handle, we use a blocking call to ensure the re-parenting completed. However during re-parenting the widget, Qt sometimes calls DefWindowProc to pass unhandled window messages back to the parent WPF widget. Since the WPF thread is blocked with calling Qt, this is a circular blocking wait, ending in a deadlock.
While I can understand the problem, we are not knowledgeable enough about the WPF GUI thread to resolve the issue.
What we tried so far:
Make the call to Qt in the background (with await) but BuildWindowCore can not be an async method.
Move the re-parenting out of BuildWindowCore, and call it async later, but the HwndHost widget requires the re-parenting to take place in BuildWindowCore, or we get a WPF error that the native widget handle is not (yet) a child widget of the WPF widget.
I'm a bit at the end of my wit. We could make the call to native code non-blocking on C++ side, and poll for its completion in a loop in C#. But how would we give the control back to the WPF GUI thread while we poll for Qt to re-parent the widget?
The most closely related SO answer suggests using await Dispatcher.Yield(DispatcherPriority.ApplicationIdle), but this was in an async method.
In pseudo-code, I'm thinking about something like:
protected override HandleRef BuildWindowCore(HandleRef HWNDParent)
{
NativeCode.beginReParenting(HWNDParent.Handle);
while (!NativeCode.reParentingCompleted()) {
// This method is async, is it clean to call it like this?
Dispatcher.Yield(DispatcherPriority.ApplicationIdle);
}
return new HandleRef(this, NativeCode.getEmbeddedWidgetHandle());
}
My questions:
Would Dispatcher.Yield() (or a similar concept) in a polling loop help to keep WPF responsive?
How can we cleanly call the async Dispatcher.Yield() method in the GUI thread, when BuildWindowCore itself can not be async?
Is this an "ok" solution, or are there better ways to not block the WPF GUI thread while calling HwndHost.BuildWindowCore()?
Your WPF pump (Dispatcher) is blocked. Async / await / Yield will not help you since you are not in an async function.
You need WPF to keep pumping while it is sat inside BuildWindowCore(). You can do this by calling your native code on a different thread, then have your WPF thread sit and pump messages until the worker thread is complete. You can do this using Dispatcher.PushFrame.
Something like this hopefully:
protected override HandleRef BuildWindowCore(HandleRef HWNDParent)
{
// call into QT in worker thread
var reParentTask = Task.Run(() => NativeCode.beginReParenting(HWNDParent.Handle));
// pump messages while we wait for QT to do its stuff
var frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
new DispatcherOperationCallback(delegate (object f)
{
((DispatcherFrame)f).Continue = !reParentTask.IsCompleted;
return null;
}),frame);
Dispatcher.PushFrame(frame);
return new HandleRef(this, NativeCode.getEmbeddedWidgetHandle());
}

C# Slow UI Performance when calling BeginInvoke frequently

I have a main form called ProxyTesterForm, which has a child form ProxyScraperForm. When ProxyScraperForm scrapes a new proxy, ProxyTesterForm handles the event by testing the scraped proxy asynchronously, and after testing adds the proxy to a BindingList which is the datasource of a DataGridView.
Because I am adding to a databound list which was created on the UI thread I am calling BeginInvoke on the DataGridView so the update happens on the appropriate thread.
Without the BeginInvoke call in the method I will post below, I can drag the form around on my screen during processing and it doesn't stutter and is smooth. With the BeginInvoke call, it's doing the opposite.
I have a few ideas on how to fix it, but wanted to hear from smarter people than me here on SO so I solve this properly.
Use a semaphore slim to control the amount of simultaneous updates.
Add asynchronously processed items to a list outside of the scope of the the method I will post below, and iterate over that list in a Timer_Tick event handler, calling BeginInvoke for each item in the list every 1 second, then clearing that list and wash, rinse, repeat until the job is done.
Give up the convenience of data binding and go virtual mode.
Anything else someone might suggest here.
private void Site_ProxyScraped(object sender, Proxy proxy)
{
Task.Run(async () =>
{
proxy.IsValid = await proxy.TestValidityAsync(judges[0]);
proxiesDataGridView.BeginInvoke(new Action(() => { proxies.Add(proxy); }));
});
}
In Windows every thread that has UI has a message queue - this queue is used to send UI messages for the windows for this thread, those message include things like mouse moved, mouse up/down, etc.
Somewhere in every UI framework there is a loop that reads a message from the queue, processes it and then wait for the next message.
Some messages are lower priority, for example the mouse move message is generated only when the thread is ready to process it (because the mouse tends to move a lot)
BeginInvoke also uses this mechanism, it send a message telling the loop there's code it needs to run.
What you are doing is flooding the queue with your BeginInvoke message and not letting it handle UI events.
The standard solution is to limit the amount of BeginInvoke calls, for example, collect all the items you need to add and use one BeginInvoke call to add them all.
Or add in batches, if you make just one BeginInvoke call per second for all the objects found in this second you probably not effect the UI responsiveness and the user won't be able to tell the difference.
Note: For the actual answer on why this is happening, see #Nir's answer. This is only an explanation to overcome som problems and to give some directions. It's not flawless, but it was in line of the conversation by comments.
Just some quick proto type to add some separation of layers (minimal attempt):
//member field which contains all the actual data
List<Proxy> _proxies = new List<Proxy>();
//this is some trigger: it might be an ellapsed event of a timer or something
private void OnSomeTimerOrOtherTrigger()
{
UIupdate();
}
//just a helper function
private void UIupdate
{
var local = _proxies.ToList(); //ensure static encapsulation
proxiesDataGridView.BeginInvoke(new Action(() =>
{
//someway to add *new ones* to UI
//perform actions on local copy
}));
}
private void Site_ProxyScraped(object sender, Proxy proxy)
{
Task.Run(async () =>
{
proxy.IsValid = await proxy.TestValidityAsync(judges[0]);
//add to list
_proxies.Add(proxy);
});
}

Unhandled exception of type 'System.ApplicationException' occurred in System.Drawing.dll

I have a winforms app. In development mode, when debugging from Visual Studio .NET 2003 (Yes, I know it's old, but this is a legacy project), I get this error when I try to open a new form. In order to open a new form I get an instance of the form and then I call ShowDialog() method, for example:
frmTest test = new frmTest(here my parameters);
test.ShowDialog();
If I press F11 (step into) when debugging it is not crashing, but If in the line where I instantiate the form I press F10 to go into next line, that is, test.ShowDialog(), then it crashes showing this error.
The complete message error is:
"An unhandled exception of type 'System.ApplicationException' occurred
in System.drawing.dll. Additional Information: An attempt was made to
free a mutual exclusion that does not belong to the process"
I have translated last part: Additional information ... since it was appearing in spanish.
The form that I am instantiating with parameters, its constructor, consists on initialize some variables for example:
public frmTest(string param1, string param2)
{
InitializeComponent();
this.param1 = param1;
this.param2 = param2;
}
private void frmTest_Load(object sender, EventArgs e)
{
// here I call a remote webservice asynchronously.
}
Also my form "frmTest" has four pictureboxes, a label, and a button. Three of the pictureboxes contain a png image (it is assigned on design time through Image property), the last picturebox contains a animated gif, also loaded in design time through Image property. Maybe the error occurs due to these images?
TL;DR: Your web request handler will execute on a different thread. Ensure you don't do anything that isn't thread-safe in that handler. You can use Invoke to dispatch your callback handler's code to the main thread.
Diagnosis
The problem here is almost certainly hiding in the missing details of your asynchronous call.
// here I call a remote webservice asynchronously.
Asynchronously is a little bit too vague to be sure what exactly is happening, but there's a very good chance that the asynchronous mechanism that you are using has executed its callback on a different thread from the main UI thread.
Overview
This is common in the .NET model. Asynchronous I/O in the .NET model makes use of threads in a thread pool to handle I/O via I/O Completion Ports (IOCP). It means that when a call like Socket.BeginReceive or WebRequest.BeginGetResponse (or any .NET asynchronous web request that uses similar technology internally) completes, the callback will execute on a thread in the thread pool, not the main thread. This may be surprising to you, since you didn't actively create another thread; you just participated in making asynchronous calls.
You must be very careful about what you do in the callback from your web request as many user-interface / Windows Forms operations are not permitted on any thread other than the main UI thread. Similarly, it may not be the UI itself that is causing you problems, you may have just accessed some resource or object that is not thread safe. Many seemingly innocuous things can cause a crash or exception if you're not careful with multithreading.
To resolve the issue:
If in doubt, in your callback, as early as you can, dispatch (a.k.a. Invoke) the code in your handler so that it runs on the main thread.
A common pattern for doing this would be something like what follows below.
Suppose you have made a call like this:
IAsyncResult result = (IAsyncResult myHttpWebRequest.BeginGetResponse(
new AsyncCallback(RespoCallback), myRequestState);
The handler might be set up like this:
private static void RespCallback(IAsyncResult asynchronousResult)
{
// THIS IS NOT GOING TO WORK BECAUSE WE ARE ON THE WRONG THREAD. e.g.:
this.label1.Text = "OK"; // BOOM! :(
}
Instead, dispatch any necessary processing back to the main thread.
private static void RespCallback(IAsyncResult asynchronousResult)
{
this.Invoke((MethodInvoker) delegate {
// This block of code will run on the main thread.
// It is safe to do UI things now. e.g.:
this.label1.Text = "OK"; // HOORAY! :)
});
}
I'm not advising this as a general best practice. I'm not saying to just immediately dispatch all your handlers back to the main thread. One size does not fit all. You should really look at the specific details of what you do in your handler and ensure you aren't doing thread-specific things. But I am saying that in the absence of any kind of explanation from you about what your asynchronous handlers are doing, the problem would likely be solved by invoking the handler code on the main thread.
Note: Of course, to fix your problem with this technique, it requires that your main thread is running. If you blocked your main thread with a (bad) technique like the one in this example then you'll have to redesign part of your app. Here's an example of something that would require a bigger rework:
// Start the asynchronous request.
IAsyncResult result=
(IAsyncResult) myHttpWebRequest.BeginGetResponse(new AsyncCallback(RespCallback),myRequestState);
// this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
ThreadPool.RegisterWaitForSingleObject (result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), myHttpWebRequest, DefaultTimeout, true);
// The response came in the allowed time. The work processing will happen in the
// callback function.
allDone.WaitOne(); // *** DANGER: This blocks the main thread, the IO thread
// won't be able to dispatch any work to it via `invoke`
Notice the WaitOne call? That blocks execution of the executing thread. If this code executes on the main thread, then the main thread will be blocked until the WebRequest completes. You'll have to redesign so that either you don't block the main thread (my recommendation) or that you more closely examine your callback handler to see why what it's doing is conflicting with other threads.
Application exceptions are not thrown by the framework itself: what-is-applicationexception-for-in-net; Problem should be in the code you have not the framework. Also be sure to check "InvokeRequired" property before taking the action and if it is, run the method using "Invoke" method. Can check c-sharp-cross-thread-call-problem for that.
May be the async call is trying to access UI thread.
Make sure you are not using control properties like TextBox.Text. If so, you just have to pass its value to the async call, or store it in a class variable before the call.
Also, inside an async call you can't assign values to that properties. Use Invoke() instead.
Try to add an exception breakpoint and VS will stop at the instruction causing the exception. The actual stacktrace may help.
Have You tried to close VS's local variable watch window? Maybe it is evaluating something for You on UI components where the accessing thread should be equal to owner thread of UI component!

Net tasks called using BeginInvoke on the main form not executing

I've used Visual Studio 2013 to build a C# application with a single form, and the application has two routines that update the screen. The routines that update the screen need to run on the main thread, so my own threads (which don't interact with the screen) call the BeginInvoke method on the main form when updates are required. However, something is happening somewhere in the application with the result that the two update routines stop executing. I've put logging into the app to track the calls to BeginInvoke and the execution of the update routines, and I can see that when this problem occurs, the BeginInvoke calls are made, but then nothing. When this happens, the whole application seems to freeze. I can't think of what might be causing this. How can I debug this? Is there any way of looking at what's queued to run on the main thread? When I run in debug and break into the application, all threads look normal, and the main thread doesn't appear to be doing anything, so why isn't it processing my pending update tasks?
The Control.BeginInvoke() adds the delegate to an internal thread-safe queue. And posts a message to the UI thread to tell it to go have a look in that queue. The message loop inside Application.Run() gets that message and goes about emptying the queue again, executing the delegates.
So if you don't see this happening then the most obvious reason is that the UI thread isn't inside the Application.Run() loop. A standard mistake you could make is waiting for the thread to complete for example. Very likely to cause deadlock. Never wait, if you need to run code after the thread completes then consider BackgroundWorker's RunWorkerCompleted event or TaskScheduler.FromCurrentSynchronizationContext().
The not-so-obvious failure mode of not seeing anything happening is that you are calling BeginInvoke() far too often. If you do this more than ~1000 times per second, give or take, then you'll flood that internal queue with too many delegates. The UI thread will actually be busy emptying that queue but can never catch up, always finding yet another delegate in the queue after executing one. It goes catatonic when this happens, not taking care of its normal duties anymore. Like responding to input and painting the windows. No fix for this, other than limiting the rate at which you call BeginInvoke(). Do keep the target in mind, you only have to do it as often as the user's eyes can perceive. Updating the UI at a rate more then 25 times per second is just wasted effort.
This might be due to the two update routines attempting to update the UI at the same time. I've seen strange UI behaviour, e.g. partially updated controls, when many UI updates occur in a short space of time when triggered by multiple interleaved events. The two routines are different routines, yes?
A possible way to solve this is to use asynchronous delegate invocation on the UI thread. In the code below I've assumed that your UI is a WinForms Form, and I've named the two routines UpdateA and UpdateB.
private bool isUpdating;
public delegate void UpdateDelegate();
private void UpdateA()
{
if (isUpdating)
{
this.BeginInvoke(new UpdateDelegate(UpdateA));
}
else
{
isUpdating = true;
try
{
// ... do UI updates for A
}
finally
{
isUpdating = false;
}
}
}
private void UpdateB()
{
if (isUpdating)
{
this.BeginInvoke(new UpdateDelegate(UpdateB));
}
else
{
isUpdating = true;
try
{
// ... do UI updates for B
}
finally
{
isUpdating = false;
}
}
}
By the way, I didn't use lock above to synchronise access to flag isUpdating, on the assumption that both UpdateA and UpdateB execute on the UI thread. They are invoked asynchronously by the worker threads via BeginInvoke.

What exactly is happening with windows form threads?

In an asynchronous OnMsgRecieved call, if I assign a value directly to a control it is not working.
Then i came to know that it was due to thread unsafe and i got following code to resolve the issue.
Now it is working. But i am not sure what it does practically. Can any one make me to understand it fully?
The code is:-
public void listener_OnMsgRecieved(string aResponse)
{
ShowResponseMessage(aResponse);
}
public void ShowResponseMessage(string aResponse)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.listBox.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(ShowResponseMessage);
this.Invoke(d, new object[] { aResponse });
}
else
{
this.listBox.Items.Add(aResponse);
label.Text = "Response received from Server :";
}
}
When ShowResponseMessage is called on a different thread from that of the UI, the InvokeRequired will return true, then you are using Control.Invoke to send a message to the Windows message queue.
The UI message pump which runs in the UI thread will pull the message and deliver it to the target control, the target control then sees that this is a message requesting that a delegate be invoked and the delegate is invoke by the control, this is now running on the UI thread and therefore the cross threading issue has been resolved.
The trick is that the delegate is not called directly on the non-UI calling thread. Using Windows messages the instruction to execute the delegate is passed to the UI thread which then executes the delegate in response to the message. 'Control.Invoke' uses the Windows [SendMessage][1], Control.BeginInvoke uses the [PostMessage][2] Win32 API to facilitate the message passing.
UI Controls cannot be update/changed from any thread other than the main thread/thread it was created on.
In your case the check InvokeRequired does the check to see if the thread that wishes to change the control is the creating thread, and if not passes the call back to the main thread/creator.
Have a look at How to: Make Thread-Safe Calls to Windows Forms Controls
If you use multithreading to improve the performance of your Windows
Forms applications, you must make sure that you make calls to your
controls in a thread-safe way.
Access to Windows Forms controls is not inherently thread safe. If you
have two or more threads manipulating the state of a control, it is
possible to force the control into an inconsistent state. Other
thread-related bugs are possible, such as race conditions and
deadlocks. It is important to make sure that access to your controls
is performed in a thread-safe way.
It is unsafe to call a control from a thread other than the one that created the control without using the Invoke method.

Categories