C#: inner workings: events, Control.BeginInvoke and program exiting = Interruption? - c#

I'm creating a program with several projects and some projects report back to the main project messages for logging purposes.
Since i am using Asynch sockets, some of these messages come back in different threads, so once they get to the main thread i check InvokeRequired and if true i use this.BeginInvoke to handle the logging.
I need to handle it in the UI thread specially in the case of the server, where i show the last logged messages on a ListBox so i can follow the progress of operations during my tests.
I know sometimes it may happen that a few messages get switched around, but for now i can live with that. For some reason if i use Invoke instead of BeginInvoke, the server will crash if i stop it while clients are connected, and won't even give any exception. But using BeginInvoke i overcame this.
My question regards understanding how events and BeginInvoke work in case of program termination. If an event is on queue or a BeginInvoke has been called just before the program is closed, will it terminate imediatly, cancelling everything? or will it perform all pending actions, in my case log the pending message, and then exit?

You'll have to delay closing the form if you want to ensure all BeginInvoked delegates are executed. You can do so by making it a two-step process, appending another BeginInvoke delegate to the queue that actually closes the form. Like this:
private bool closing;
protected override void OnFormClosing(FormClosingEventArgs e) {
if (!closing) {
closing = true;
// Do your stuff
//...
this.BeginInvoke(new Action(() => this.Close()));
e.Cancel = true;
}
base.OnFormClosing(e);
}

When you call BeginInvoke to update UI, the code will be executed by a thread from the threadpool. And if the code raises an exception, it will only terminate the thread, not the whole application. That's why you have seen that your program didn't crash.
When BeginInvoke had just been called, and the program was terminated immediately. The remaining operations (logging ) won't be executed, because the thread from the threadpool

Related

Application.Exit(): Does it start a new thread (my program continues execution in parallel)?

I have a multi-threaded application, and both in the main UI thread and in other background threads, I have stop-methods that call Application.Exit().
The weird thing is that after the call, the program continues on to the next line (and then eventually exits). The obvious problem with this can be explained with the simple code below:
if (XYZ) Application.Exit();
Globals.Instance.LoggerDictionary["ApplicationLog"].Log("Bla bla...");
And this:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
var button = sender as Button;
if (button != null && string.Equals(button.Name, #"CloseButton"))
{
//FormClosing event raised by a user created button action
}
else
{
//FormClosing event raised by program or the X in top right corner
Globals.Instance.LoggerDictionary["ApplicationLog"].Dispose();
Globals.Instance.LoggerDictionary["OtherLog"].Dispose();
MemoryHandler.Instance.Dispose();
}
}
As seen the FormClosing method ensures that cleanup of unmanaged resources is done. So, in many cases the application moves on to the line below Application.Exit(), and, in the example above, try to write something to the Log, which has already been disposed by the FormClosing() method.
My question is therefore: Does Application.Exit() spawn a new thread where FormClosing() is run from? If not, then why does it continue on?
http://msdn.microsoft.com/en-us/library/system.windows.forms.application.exit(v=vs.110).aspx
Informs all message pumps that they must terminate, and then closes all application windows after the messages have been processed.
This method does not terminate the process. Instant termination is rarely a useful shutdown model because it is unclear what useful shutdown actions would be skipped.
If this method does not terminate the process then clearly your code must continue to run.
This is normal and the right way to shut down the app. If you want to skip certain logic, set a flag bool isShuttingDown and react to it.
No, it does not start a new thread. It also doesn't immediately kill the UI thread. The whole point of Application.Exit is to gracefully exit the application. All forms will be asked to be closed, resources will be cleaned up, all pumped through the main application loop. When the application loop next becomes idle, rather than waiting for more messages, it will instead stop pumping messages and the application will continue running after the call to Appliaction.Run that created the message loop in the first place. That thread can then go on to do whatever (usually end; unless you've added more code).
No it does not spawn a extra thread. Looking at the reference source inside the function it will call each form's FormClosing event, it then returns control to the caller. Once the caller completes and control returns to the message loop that is when the program will actually shut down.
All of this happens on the single UI thread.

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.

Serial port running on a thread using MVP

I have a class called SerialClient that sends/receives bytes over a serial port. When SerialClient.Start() is called it goes into an infinite while loop, until SerialClient.Stop() is called. The class has some properties, for simplicity lets say SerialClient.PropA, SerialClient.PropB.
I need to use this in a GUI. Where by on the GUI you can call Start, Stop and read the properties as they change.
In order to use this in a GUI, obviously SerialClient needs to operate in a thread as its an endless loop. So, I have setup the view with properties to match that of SerialClient. The view calls Start() and Stop() on the presenter.
In the presenter I create a new thread and call start on an object of SerialClient. The problem is when _serialClient throws an exception the presenter cannot catch it, and also if the properties like (SerialClient.PropB) change and call their changed event handlers, they need to be invoked on the GUI thread. I tried using the background worker, but couldn't get it working (changing properties still hit the UI from the non-UI thread).
Thread thread = new Thread(_serialClient.Start);
thread.IsBackground = true;
thread.Start();
There must a simple solution I am over looking. The GUI just needs to call methods and read properties, and prevent exceptions crashing the whole application.
Any ideas?
You hit 2 of the common problems usually seen when dealing with multithreaded application in C#:
Dealing with exception in the background thread. When exceptions occurs in the background thread, they travel up the stack, from caller to caller to see if anyone is able to catch that exception. If the original call occurs from outside your own calls (for example, a callback from a serial port or a timer) you may or may not be notified of the exception. As a typical solution to this, what I have seen is to wrap in a try-catch the code that can throw the exception and to have an event handler push the exception to a thread that will be able to handle the exception appropriately (log, notify the user, terminate, all of the above)
Events are always excuted on the thread that calls them. You have to manually marshall the call to the UI thread using Dispatcher and Invoke. The most succint code to do it I found is here
void someEvent_Handler(object sender, SomeEventEventArgs e)
{
if (this.Dispatcher.CheckAccess())
{
// do work on UI thread
}
else
{
// or BeginInvoke()
this.Dispatcher.Invoke(new Action(someEvent_Handler),
sender, e);
}
}

Control.Invoke() hangs application

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

Object Disposed exception and multi thread application

I have an application that start System.Threading.Timer, then this timer every 5 seconds read some information from a linked database and update GUI on main form of application;
Since the System.Threading.Timer create another thread for the Tick event, i need to use Object.Invoke for updating User Interface on the main Form of application with code like this :
this.Invoke((MethodInvoker)delegate()
{
label1.Text = "Example";
});
The app work very well, but sometimes when the user close the main form and then close the application, if the second thread on timer_tick event is updating the user interface on main thread the user get an ObjectDisposedException.
How can i do for stop and close the threading timer before closing the main form and avoiding then Object disposed exception ?
This is a bit of a tricky proposition as you must ensure the following on a given Close event
The timer is stopped. This is fairly straight forward
The control being updated isn't disposed when the delegate is run. Again straight forward.
The code currently running off of a timer tick has completed. This is harder but doable
There are no pending Invoke methods. This is quite a bit harder to accomplish
I've run into this problem before and I've found that preventing this problem is very problematic and involves a lot of messy, hard to maintain code. It's much easier to instead catch the exceptions that can arise from this situation. Typically I do so by wrapping the Invoke method as follows
static void Invoke(ISynchronizedInvoke invoke, MethodInvoker del) {
try {
invoke.Invoke(del,null);
} catch ( ObjectDisposedException ) {
// Ignore. Control is disposed cannot update the UI.
}
}
There is nothing inherently wrong with ignoring this exception if you're comfortable with the consequences. That is if your comfortable with the UI not updating after it's already been disposed. I certainly am :)
The above doesn't take care of issue #2 though and it still needs to be done manually in your delegate. When working with WinForms I often use the following overload to remove that manual check as well.
static void InvokeControlUpdate(Control control, MethodInvoker del) {
MethodInvoker wrapper = () => {
if ( !control.IsDisposed ) {
del();
}
};
try {
control.Invoke(wrapper,null);
} catch ( ObjectDisposedException ) {
// Ignore. Control is disposed cannot update the UI.
}
}
Note
As Hans noted ObjectDisposedException is not the only exception that can be raised from the Invoke method. There are several others, including at least InvalidOperationException that you need to consider handling.
System.Timers.Timer is a horrible class. There is no good way to stop it reliably, there is always a race and you can't avoid it. The problem is that its Elapsed event gets raised from a threadpool thread. You cannot predict when that thread actually starts running. When you call the Stop() method, that thread may well have already been added to the thread pool but didn't get around to running yet. It is subject to both the Windows thread scheduler and the threadpool scheduler.
You can't even reliably solve it by arbitrarily delaying the closing of the window. The threadpool scheduler can delay the running of a thread by up to 125 seconds in the most extreme cases. You'll reduce the likelihood of an exception by delaying the close by a couple of seconds, it won't be zero. Delaying the close for 2 minutes isn't realistic.
Just don't use it. Either use System.Threading.Timer and make it a one-shot timer that you restart in the event handler. Or use a System.Windows.Forms.Timer, it is synchronous.
A WF Timer should be your choice here because you use Control.Invoke(). The delegate target won't start running until your UI thread goes idle. The exact same behavior you'll get from a WF timer.
Create two booleans called 'StopTimer' and 'TimerStopped'. Set the timer's AutoReset property to false. Then format the Elapsed method to the following:
TimerStopped = false;
Invoke((MethodInvoker)delegate {
// Work to do here.
});
if (!StopTimer)
timer.Start();
else
TimerStopped = true;
This way you are preventing a race condition, checking if the timer should continue and reporting when the method has reached its end.
Now format your FormClosing event as follows:
if (!TimerStopped)
{
StopTimer = true;
Thread waiter = new Thread(new ThreadStart(delegate {
while (!TimerStopped) { }
Invoke((MethodInvoker)delegate { Close(); });
}));
waiter.Start();
e.Cancel = true;
}
else
timer.Dispose();
If the timer hasn't stopped yet, a thread is launched to wait until it has done so and then try to close the form again.

Categories