Control.Invoke() hangs application - c#

I'm showing an animation while my control is loading the data. When the thread finishes, I hide the animation and show the control. So I'm executing this code from a thread:
protected void InvokeEnableBackControl()
{
if (this.InvokeRequired)
{
this.Invoke(new OpHandler(EnableBackControl));
}
else
{
EnableBackControl();
}
}
Sometimes, when I execute this code, the main thread gets hanged in the following code:
protected virtual void EnableBackControl()
{
if (overlayAnimation.TargetControl != null)
{
overlayAnimation.TargetControl.BringToFront();
}
overlayAnimation.SendToBack();
overlayAnimation.Enabled = false;
overlayAnimation.Visible = false;
}
I'm not sure if it's hanged setting the Enable or Visible property. Do you know any circumstance that may hand the application calling these properties from a Control.Invoke?

Note that Control.Invoke is synchronous, so it will wait for EnableBackControl() to return. Consider using Control.BeginInvoke, which you can "fire and forget."
See this answer: What's the difference between Invoke() and BeginInvoke()

I've run into problems before when I'm executing .Invoke on a background thread while my main thread is still busy - this gives the impression that the app is hung, because the .Invoke just sits there, waiting for the main thread to respond that it's paying attention. Possible causes:
Your main thread is blocked waiting for something
Your main form currently had a modal dialog up, so it's not listening to new requests
Your main thread is spinning, either continually checking if something is finished or doing new work. In my case, the main thread spent the first minute spinning up background threads in a tight loop, so it wasn't listening for any .Invoke requests from background threads.
When you attach the debugger, pay special attention to what your main control MessagePump thread is doing - I suspect its lack of attention is the cause of your trouble. If you identify that it's a tight loop in your main thread that's not responding, try inserting a .DoEvents in the loop, which will pause execution and force the main thread to empty the message pump and route any outstanding requests.

Run in debug, make app hang and then pause debug in Visual Studio and inspect threads.

What I discovered is that the actual drawing/painting of controls can be quite slow, esp if you have a lot of them and/or use double buffering for smooth refresh. I was using BeginInvoke to update a listview control from data I was receiving from a socket. At times the updates were happening so fast that it was freezing the app up. I solved this by writing everything I received in the sockets async receive to a queue, and then in a seperate thread dequeuing the data and using BeginUpdate and EndUpdate on the listview and doing all the outstanding updates in between. This cut out a ton of the extra redrawing and made the app a lot more responsive.

You have to use BeginInvoke inested Invoke see this Link

Related

Application Freeze in loop when using Sleep

I have an application that I made to connect to a device using telnet, the application freeze/crash when I started it .. I have System.Threading.Thread.Sleep(3000); in couple locations of the application. I was wondering, is there a way to have the application active and buttons are useable but the some operations are only impacted by the sleep operation?
Thanks in advance.
Don't use Thread.Sleep, especially on the UI thread. This will cause a hang - by design.
Since you're using .NET 4.5, you can use await Task.Delay(3000); to asynchronously "sleep", which won't block the UI. However, this is typically a sign of a poor design - "waiting" is something that really shouldn't need to happen in a UI application in general. There are typically better approaches, such as using await on the asynchronous operation for which you're waiting, etc.
This requires a bit of an explanation. There are some threads that are special in this case the ui thread where the rendering of your Ui happens and the events from the input devices are handled. If this thread spends time doing any calculations windows will state that your application has frozen. Since you are using Thread.Sleep on it you get this result.
Articles to understand the problem
http://msdn.microsoft.com/en-us/library/ms741870(v=vs.110).aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/dd744765(v=vs.85).aspx
Recommended Solutions
On the Button press dispatch a thread that goes and does the work that you need to happen. On the meantime change the cursor for the mouse to indicate that work is happening or show a progress bar. Once it finishes you can fire(dispatchet) an event that changes the ui.
I would do something similar to:
// The Work to perform on another thread
ThreadStart start = delegate() { // ... // This will work as its using the dispatcher
DispatcherOperation op = Dispatcher.BeginInvoke( DispatcherPriority.Normal, new Action<string>(SetStatus),
"From Other Thread (Async)");
DispatcherOperationStatus status = op.Status; while (status != DispatcherOperationStatus.Completed) { status = op.Wait(TimeSpan.FromMilliseconds(1000));
if (status == DispatcherOperationStatus.Aborted)
{ // Alert Someone } } }; // Create the thread and kick it started! new
Thread(start).Start();
More Examples at:
http://msdn.microsoft.com/en-us/magazine/cc163328.aspx
If you are calling sleep within your application it will do just that. If you do not want your application to hang, you will need to create a new thread that does whatever monitoring and waiting you want it to do, if a particular condition you are looking for is met, then use a callback to your parent thread to perform whatever task you want to do.

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.

Unable to close new WPF window until all UI threads are returned even if dispatcher priority is set to background

I am new to WPF and making it up as I go along so apologies if I have done anything drastically wrong.
I have a main window that makes a new 'error window' once particular user controls have completed their business. This new error window returns a 'loading placeholder' to UI whilst a background thread is updating another part of the 'error window'.
ErrorsWindow errorWindow = new ErrorsWindow();
errorWindow.LoadingPlaceholder.Text = string.Format(#"Loading...
Please wait {1} minutes and {0} seconds to see potential errors",
ConfigurationManager.AppSettings["ErrorWindowWaitSeconds"],
ConfigurationManager.AppSettings["ErrorWindowWaitMinutes"]);
errorWindow.Show();
this.Dispatcher.BeginInvoke((Action)(() =>
{
errorWindow.SetupWindow();
}), System.Windows.Threading.DispatcherPriority.Background);
So my errorWindow shows up in the UI with the loading placeholder text set correctly. The UI then waits 1 minute 30 seconds for the errorWindow.SetupWindow() method to complete. The issue is that during this wait period I cannot close the window until the errorWindow.SetupWindow() method has completed.
Is there a way to allow the window to close and just abort the background thread?
EDIT: I cannot use a backgroundworker or a task as I need to update the UI elements inside the errorWindow.SetupWindow() method
Thankyou in anticipation
Invoking anything on Dispatcher (if Dispatcher is of UI thread) will run your delegate on UI thread only. Hence, you can't close the window till UI thread is busy somewhere else.
Setting priority DispatcherPriority.Background won't make it run on background thread. It set's the delegate DispatcherPriority to Background. It means that all queued delegates on Dispatcher with priority higher than Background will run first before your delegate gets time to execute.
In case you want to run your operation on background thread, use Task or BackgroundWorker.
As per definition from MSDN:
Executes the specified delegate asynchronously at the specified
priority on the thread the Dispatcher is associated with.
As stated above it runs delegate on associated thread of dispatcher. (which might be in your case is UI thread).
I found the answer to my question on another stackoverflow post here:
How to make some Tasks change my WPF controls
It involves doing the long running task on another thread(using System.Task) then using the dispatcher on the separate thread to affect the UI thread with any UI related changes.

Deadlock using Control.Invoke?

I'm building an app using TPL in VS2010 Ultimate. The most of the times I run the app it becomes unresponsive when I Call DoRepresentation() from the UI's thread.
void DoRepresentation()
{
Parallel.ForEach(cgs, loopOptions, g =>
{
UpdateRepresentation(g);
});
}
void UpdateRepresentation(object g)
{
view.Invoke(new Action(() =>
{
representation = new MyRepresentation(g);
}));
}
I don't know why the app is becoming unresponsive. Am I having a deadlock?
Inside MyRepresentation I do some calls to OpenGL.
view is a Control inside Form1 (the main form).
When the app become unresponsive I pause it from the VS IDE and here's the info I get
In the "Parallel Tasks" window I get the following:
ID Status Message<br>
1 ?Waiting Task1 is waiting on object: "Task2"<br>
2 ?Waiting No waiting information available<br>
In the "Call Stack" window I get the following:
[In a Sleep, wait, or join]<br>
[External Code]<br>
Test.dll!Render.DoRepresentation()<br>
App1.exe!Form1.Button1_Click<br>
Any help will be appreciated.
Yes, you are having a deadlock. What Parallel.ForEach() does is that it runs the iterations using one or more threads including the current one and then blocks the current thread until all iterations are complete.
This means that if you call DoRepresentation() from the UI thread, you get a deadlock: the UI thread is waiting for iterations on other threads to finish, while those other threads are waiting for Invoke() to finish, which can't happen if the UI thread is blocked.
Also, in your case, using Parallel.ForEach() doesn't make any sense (assuming this is your actual code): you run new MyRepresentation() on the UI thread.
I don't understand what exactly is the code doing (it seems it overwrites representation in each iteration), but I think you should run ForEach() from a background thread. This means DoRepresentation() will return before it finishes its work and so Invoke() will work correctly.
In general, it's not a good idea to block the UI thread for a long time, so you should run any time-consuming code on another thread.
you can use the BeginInvoke insteed of Invoke Method. if you still need then you can lock an object and make sure that this will not be accessible from the other thread until its realized.
using the Begin Invoke Method
void UpdateRepresentation(object g)
{
view.BeginInvoke( new Action(() =>
{
representation = new MyRepresentation(g);
}));
}
Using the Lock
void UpdateRepresentation(object g)
{
lock(this)
{
view.Invoke(new Action(() =>
{
representation = new MyRepresentation(g);
}));
}
}
This comment applies to my specific app, which is a Windows app in C#: Using a Lock did not work for me either, and the application just froze up.
BeginInvoke worked, but I didn't like the effect of having UI controls being updated asynchronously.
I ended up starting the main process as a separate thread (System.Threading.Tasks.Task), which would start and instantly give me back control of the main thread. Afterwards, while waiting for several other tasks to end execution in a loop, I also ended up having to insert this line: System.Windows.Forms.Application.DoEvents() to enable the system to process all messages waiting in the queue. Now it works right for my application. There might be another way to skin this cat, but it works now.

Deadlock when invoking the UI thread from a worker thread

I have a deadlock when I invoke the UI thread from a worker thread. Indeed, the worker thread is blocked on the invoke line:
return (ucAvancementTrtFamille)mInterfaceTraitement.Invoke(d, new object[] { psFamille });
The weird thing is that the UI Thread (which, correct me if I'm wrong, is the main thread) is idle.
Is there any way to:
see which thread I'm actually trying to invoke?
see what said thread is really doing?
We can see in the image below, the worker thread (ID 3732) blocked on the Invoke line, and the MainThread is idle in the main function of the application.
Edit: Here is the stack of the main thread:
Edit2: Actually, I paused the the program a second time, and here is what the stack looks like:
Edit3: Workaround found
I finally found a workaround. The problem is apparently due to an async wrapper race
condition issue. The workaround is to use BeginInvoke and wait for it with a timeout. When it times out, invoke it again and loop until it finally returns. Most of the time, it actually works on the second call.
IAsyncResult ar = mInterfaceTraitement.BeginInvoke(d, new object[] { psFamille });
while (!ar.AsyncWaitHandle.WaitOne(3000, false))
{
ar = mInterfaceTraitement.BeginInvoke(d, new object[] { psFamille });
}
// Async call has returned - get response
ucAvancementTrtFamille mucAvancementTrtFamille = (ucAvancementTrtFamille)mInterfaceTraitement.EndInvoke(ar);
It's not pretty but it's the only solution I found.
The Main thread doesn't look idle. Your screen shot shows it current location at ECM.Program.Main. That can't be correct, if it is idle then it is inside Application.Run(), pumping the message loop. Which is required for Invoke() to complete.
Double-click the main thread and switch to the Call Stack window to find out what it is really doing.
Have you tried using BeginInvoke instead of Invoke? BeginInvoke is asynchronous.
You are correct. The Main Thread is the entry point to the application which is normally the location of the call to Application.Run which gets the message loop going. So that should be the UI thread unless you have done something out of the ordinary in regards to the message loop which is unlikely.
In the Thread window you can right click on the Main Thread and select Switch to change the debugging context to that thread. The Call Stack window will then show the location of the current executing method.
If your worker thread really is blocked on the Control.Invoke call and the UI thread is idle as you claim then the problem could be with the execution of the instructions within the delegate that is being marshaled or the message loop as not yet been started. The later seems plausible since your screen shows the location of the Main Thread as Main.
Have you tried using a BackgroundWorker instead. If you use it it will save you a lot of this.Invoke and InvokeRequired calls.
I believe that if you create a new thread and make it execute the line you are showing you won't have a deadlock. I will try find old code of mine and post it here.
Are you using Visual Studio 2008 ?
If the answer is yes, you should try with Visual Studio 2010. It's a known bug.
Good luck !

Categories