I have a background worker thread continuously updating the data displayed in a window from a network source. I also have a button which will fire an event.
My question is, at what stage (relative to the background worker execution) is the event method executed? Is it similar to threads in that they happen simultaneously? I.e, will the background worker will still be running whilst my button click method is executing? In which case, I will need to use locking. Or will the background worker pause until the button click method has terminated?
Events raised by UI controls (e.g. buttons) execute in the main thread, a.k.a. the UI thread. Events you raise yourself are raised on whatever thread you raise them on. All event raisings block the execution of their own thread until they complete. They're not very special, when you call them: Just a little syntactic sugar around calling an arbitrary list of delegates.
In the absence of any explicit synchronization code, any other threads humming along the background will merrily continue to execute.
If you need or want to communicate between an event handler in the UI thread and a worker thread, you'll need to write explicit code to do so. Nothing special here: Just two threads.
And if you've got both an event handler and a thread putting their greasy little mitts on the same object, and if the operations on that object are not atomic, you're correct: You'll need locking. Thread-safe collections may come in handy.
Related
Are event handles like this
notifyIcon.BalloonTipClosed += new EventHandler(delegate(Object sender, EventArgs e)
{
// ...
});
guaranteed to run on the UI thread, so I don't need to call Invoke or BeginInvoke methods to update controls?
Thanks in advance.
Yes, they are.
User interface events are caused by a message in the message queue, and it's the UI thread that runs the message pump that handles the messages.
An event from the System.Timers.Timer class would not run in the UI thread, because it's not an UI related event. An event from the System.Windows.Forms.Timer class would run in the UI thread, as it's designed to run in a window and uses the message queue for the events.
To be clear - event handlers for events raised by UI objects should be. Event handlers, in general, no.
E.g. event handlers for NetworkAvailabilityChanged won't be called on the UI thread.
But within the classes for e.g the System.Windows.Forms namespace, yes, they should be.
Event Handlers, that are associated with the UI, run on the UI thread, the primary thread of a desktop application. That's the reason in some cases your UI may be get frozen. This is happening because the event handler's code takes too much to be executed in these cases. For this reason, we have adopted the paradigm of asynchronous programming. So when we have to wait for an I/O or a network related task to be completed, it's ins't needed this to be done by the UI thread. This can be done by another thread. Doing so, we avoid to freeze the UI.
I have a C# program that is checking for the existence of files and registry keys and using AppendText() on a Form.Textbox for every file and registry key it is looking for.
This is running in an asynchronous BackgroundWorker and now my background worker is actually processing so quickly that my UI thread gets clogged up with AppendText commands and the program crashes. How can I synchronize the BackgroundWorker and UI thread so that the BackgroundWorker doesn't start processing again until the UI thread is ready?
You have a BackgroundWorker, so you have everything you need. The progress event is called on the UI thread, so if the worker reports progress in the standard way (by calling ReportProgress(int32, object), and passing the string to be appended as the second parameter, the form's progress handler can call AppendText. The background thread will never outrun the UI that way.
I suspect you're calling BeginInvoke to update your UI. Another way to solve the problem would be to call Invoke.
You can do much better if you have your background worker save up, say, 10 lines, and then pass them all to the progress event at once. That'll reduce the overhead of updates and cause your background thread to process faster.
One way that comes to mind is queuing the commands and allowing the UI thread to handle them at its own speed :: IE create a generic list (let's call it appendtext) of the arguments, the background worker adds to the list and the UI thread reads, calls, then deletes from the list
Is there anyway to run a large number of UI updates without effecting the main thread in a C# winforms application?
I would like to avoid a long delay when a user clicks a specific event (which in my case is many close form calls to dispose of memory)
I know i can use BackgroundWorker to perform lengthy operations in the "do work" event, but the problem is that you cant change any UI in this event (it will cause a cross thread exception) - so i cant put my large number of close form calls here.
And I cant put the close form calls in the "worker completed" event because this is run on the main thread, and will eventually lockup the main thread causing a bad user experience.
I have thought about spawning a thread to handle closes only when the appication session is idle, but not sure if this is going to be a bit messy.
You should use ProgressChanged event of BackgroundWorker to update UI. To enable this feature set WorkerReportsProgress property of your BackgroundWorker instance to true. Then you can update UI many times by sending data from DoWork event handler:
backgroundWorker.ReportProgress(percentage, yourCustomData);
It is recommended to Make Thread-Safe Calls to Windows Forms Controls. Here is the reason:
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 as well, including race conditions
and deadlocks. It is important to ensure that access to your controls
is done in a thread-safe way.
The .NET Framework helps you detect when you are accessing your
controls in a manner that is not thread safe. When you are running
your application in the debugger, and a thread other than the one
which created a control attempts to call that control, the debugger
raises an InvalidOperationException with the message, "Control control
name accessed from a thread other than the thread it was created on."
This exception occurs reliably during debugging and, under some
circumstances, at run time. You are strongly advised to fix this
problem when you see it.
You can disable that exception:
Form.CheckForIllegalCrossThreadCalls = false;
But controls could (and sometime will) stop working.
To set the stage, I have a custom class called Scheduler that holds multiple Task objects (this is a custom class as well). Each task has a BackgroundWorker object to run long running work. I am currently doing some testing of having many of these tasks executing quickly and being handled at the same time.
In my Task object, I raise an a custom event (TaskCompletedEvent) in the TaskWorkerCompleted handler to alert the scheduler that a task is completed. The scheduler uses the same event handler for every task's TaskCompletedEvent.
What I want to know is if I am currently in the Scheduler TaskCompletedEvent handler executing code and another event finishes up, what happens? Both are going to be on the UI Thread, so does the one currently in the event handler finish up before the other one proceeds? I'm getting confused on what is going to happen when two events finish simultaneously and need to be handled.
No, the events themselves don't know about the UI threads. So the events will be dispatched in the same thread where they are fired (this is most probably in the backgroundworker's thread, right?)
If your both events are fired in the UI thread, this cannot be simultaneous (after all, the UI thread is executing either one or another event firing code), so the second event isd perhaps going to be fired when the first event is finished with firing and dispatching.
If you want the Scheduler to marshal the events to the UI thread, that is a slightly different story. Your code which needs to be executed at the UI thread will be actually posted into a kind of event queue of that thread, and whatever event-firing code happens to be first, gets executed first.
I have a weird behavior in my GUI code. If the user produces a lot of events in a short time, it happens that a running event handler method gets interrupted by another event handler method.
Since everything runs in the same thread (GUI thread) everything should run sequential and an interruption should not be possible, or do I misunderstand something?
Thanks for your advise,
Eny
No, that doesn't happen. You are right in your understanding that the thread runs sequentially.
The GUI thread can be interrupted but only to run a different thread, it will not re-enter the GUI thread to handle another event. A thread only has one instruction pointer and thus can only be in one place in the code, it can not be interrupted by itself.
If you are experiencing something that look like the GUI thread is re-entered, the reason is something else.
The GUI thead can however "interrupt" itself by calling the Application.DoEvents method.
You are correct, in a single threaded application, event should be run sequentially. There are a few exceptions:
An event is fired and calls the first event handler in its subscriber list. The event handler fires an event of its own, which calls other event handlers. In this case, it would appear that the event was interrupted, but it was not. When the original event handler completes, the next event handler in the list will be called.
An event handler calls the Application.DoEvents() method. This will suspend the current event and process any messages waiting in the message queue (which will usually fire events of their own), and when it has finished processing all messages, it will return to the event. A problem may occur when Application.DoEvents() causes a recursive call to the event which called it, as a result of firing an event from one of the messages it processed.
Event handlers may be executed on different threads. Some events are not fired on the UI thread, and may fire on their own thread. This could cause events to be fired out of order and interrupt each other on a thread contexts switch. Make sure that the events you consume are fired on the UI thread, and if not, Control.Invoke() them onto the UI thread. An example of an event that is fired on a separate thread, possibly without you being aware of it, is the System.Threading.Timer.Elapsed event.