Updating controls in Main Thread using EventHandler - c#

I'm using this to update a control in the main thread from another thread:
private void ShowHourGlassSafe(bool visible)
{
this.Invoke((EventHandler)((s, ev) => pictureBoxHourGlass.Visible = visible));
}
I wonder what are the implications of doing it this way or if is there any risk this is going to fail?
From the many examples are there for the same thing I could not find one like this.
It could be that it's simply wrong?

Well, you've picked a rather odd delegate to choose, as you've chosen one that has two parameters despite the fact that none are needed nor will be provided. I don't know if that will cause it to break, but it's certainly doing nothing to help. You're most likely best off using a delegate that takes no parameters and returns no values, such as:
private void ShowHourGlassSafe(bool visible)
{
this.Invoke((MethodInvoker)(() => pictureBoxHourGlass.Visible = visible));
}
Other than that, the fundamental concept of what you're doing is perfectly fine.

Typical problems with this kind of code:
You'll deadlock if the UI thread is doing something unwise like waiting for the thread to complete. There's no point in using Invoke, that blocks the worker thread for no benefit, just use BeginInvoke. Solves the deadlock potential and the unnecessary delay.
You'll crash when the UI was closed and pictureBoxHourGlass was disposed. Ensuring that the thread is no longer running before allowing the UI to close is very commonly overlooked. Just displaying an hour glass isn't enough, you also have to take countermeasures to prevent the user from closing the UI. Or otherwise interlock it with a way to cancel the thread first
The user will typically be befuddled when an hour glass shows up without him doing anything to ask that something gets done. The 99% correct case is that you display the hour glass with code in the UI thread and then start the thread. And hide it again when the thread completes. Easiest to do with the BackgroundWorker or Task classes, they can run code on the UI thread after the job was done.
Favor the Action delegate types for consistency:
private void ShowHourGlassSafe(bool visible) {
this.BeginInvoke(new Action(() => something.Visible = visible));
}

Related

Mutual exclusive operations in UI thread with Dispatcher.PushFrame and Application.DoEvents

The situation
I'll try to explain my Problem with a small example. I have a class that manages a view-stack. Replaces views shows and initializes them etc.
class ViewManager()
{
void ReplaceView()
{
RemoveView(...);
InitializeView(...); // this code may call Application.DoEvents()
AddNewView(...);
}
void ShowModalView()
{
ShowView();
Dispatcher.PushFrame()
....
// wait until view can be removed
RemoveView();
}
void RemoveView()
{
...
}
// ... more functions
}
Because the ViewManager does a lot with UI elements, other Threads uses the ViewManager through Dispatcher.Invoke.
Dispatcher.Invoke(new Action(() => m_viewManager.Remove(someView)));
If now multiple threads Invoke actions on the ViewManager, and one of them calls deep down somewhere in the code Application.DoEvents or DispatcherPushFrame, a second MessageLoop is spawned that will invoke another method o n the view Manager.
The Problem:
ShowModalView is called and calls PushFrame.
During ShowModalView another thread calls ShowModalView or ReplaceView.
Because the new message loop executes all tasks queued to the dispatcher this method are also executed.
Therefore two methods of the ViewManager are executed "at the same time" - or better because it is the same thread - nested in each other.
Locking inside the ViewManager is useless, because it is all the same thread. A semaphore might freeze the UI thread, because during the Message loop of the "ShowModalView" another thread can invoke ShowModalView on the dispatcher and that will freeze the UI thread.
The Questions:
During the "ShowModalView" the UI thread should handle input / paint etc but should not handle other tasks invoked through "Dispatcher.Invoke" Is this possible?
Do you have other Ideas to solve this problem?
Thank you for your hints and answers
Manuel
EDIT:
One solution might be to get rid of all DoEvents and PushFrame code. This is very hard to achieve but probably the only right solution. This post explains a part of my Problem
Use of Application.DoEvents
As Servy said, get rid of Application.DoEvents() and Dispatcher.PushFrame is the only clean solution. Sometimes this will cause a lot of refactoring but it is worth the effort.

Dispatcher.CurrentDispatcher.BeginInvoke Not Invoking

I have a FileSystemWatcher and the events raised by this when a watched file changes are raised on a different thread from the UI thread. To avoid and cross-thread acess volation fun, I am attempting to use
public void RaisePathChanged(object sender, RenamedEventArgs e)
{
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() =>
{
// Some code to handle the file state change here.
}));
}
This compiles fine and the RaisePathChanged is fired as it should be. However, the code inside the delegate Action(() => { /*Here*/ }) never gets called/invoked, the code is merely skipped.
Why is the code being skipped, how can I fix it and is this the best way to insure code is run on the thread that created it in WPF?
Thanks for your time.
You are mixing up things.
Dispatcher.CurrentDispatcher is not the same as Application.Current.Dispatcher.
The second one is the one you seem to be looking for.
Take a look at this.
Dispatcher.CurrentDispatcher vs. Application.Current.Dispatcher
Try it out with application dispatcher.
Dispatcher.CurrentDispatcher is the dispatcher of the "current" thread - in this case the thread RaisePathChanged is executing on.
When you say Dispatcher.CurrentDispatcher .NET will create a new dispatcher if there was none.
It will however not Run() said dispatcher!
So when you schedule something on it (with BeginInvoke) it will not actually be executed unless that dispatcher is running.
That likely answers your first question (Why is it not Invoking?)
To avoid cross-thread access violation, you need the dispatcher of the thread that created whatever you are trying to protect and make sure it is a running dispatcher.
If whatever you are trying to protect was created on the default GUI thread, then use Application.Current.Dispatcher like the previous answer says, otherwise you will need to do a bit more explaining and post a bit more code before we can answer your second question. http://www.diranieh.com/NET_WPF/Threading.htm has a pretty short intro into the subject.

invoke during background worker

I need to invoke this: string input_ip_r = listView1.Items[lc].SubItems[1].Text;
so I used
if (InvokeRequired)
{
this.Invoke(new MethodInvoker(function));
return;
}
This worked but now I have put it into a BackgroundWorker and using this
if (InvokeRequired)
{
this.Invoke(new MethodInvoker(bw.RunWorkerAsync));
return;
}
it gives an error that you can only run BackgroundWorker one at a time.
So how do I invoke while in the Backgroundworker?
1) Don't put RunWorkerAsync as the method to invoke. It's not actually running the method that you think. What you should really put there is something like this:
this.Invoke(new MethodInvoker(MethodToUpdateUI));
MethodToUpdateUI should be some new method that you create that specifically does whatever UI updates should be made in this context.
2) There's no need for InvokeRequired. You're in a background thread. Invoking will always be required.
To be honest, the entire patter of if(invoke required) call myself else do stuff is an odd construct which I dislike. InvokeRequired should pretty rarely be used. You should almost always know whether you're in the UI thread or a background thread, if you don't, chances are something wrong (either you're always in one or the other and you just don't know which, or it shouldn't be non-deterministic). Usually this means having methods that must be run in the UI thread. If you're already in the UI thread you just call them, if you're in a background thread and know it then you call Invoke first.
On top of that, Invoke works just fine even if you call it when you're already in the UI thread, so there's really no significant negative consequences to just calling Invoke regardless of whether you're in a background thread or already in the UI thread.
3) Usually it's best to separate code for solving business problems from UI code. It's code smell to be invoking from within DoWork's handler. If this is right near the end, you should probably be adding an event handler to RunWorkerCompleted. If you're calling this periodically to update the UI with progress of the worker, you should be using ReportProgress and handling the ProgressReported event. For getting info from the UI for use in a long running task you should access it before starting the background task. For exceptional cases that aren't any of those, it may be appropriate to use Invoke, but the remaining cases ought to be rare.
I'm not quite sure how you want to use the values, but just to give you an example, you could easily just do this in the BackgroundWorker thread:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
string input_ip_r = "";
this.Invoke(new Action(() =>
{
// Don't know what "lc" is (a loop variable?)
input_ip_r = listView1.Items[lc].SubItems[1].Text;
}));
}
See this answer for other ways of doing the same (this is for >= .Net 3.5)

How can I check if a function is being called on a particular Thread?

If I have Thread A which is the main Application Thread and a secondary Thread. How can I check if a function is being called within Thread B?
Basically I am trying to implement the following code snippit:
public void ensureRunningOnCorrectThread()
{
if( function is being called within ThreadB )
{
performIO()
}
else
{
// call performIO so that it is called (invoked?) on ThreadB
}
}
Is there a way to perform this functionality within C# or is there a better way of looking at the problem?
EDIT 1
I have noticed the following within the MSDN documentation, although Im a dit dubious as to whether or not its a good thing to be doing! :
// if function is being called within ThreadB
if( System.Threading.Thread.CurrentThread.Equals(ThreadB) )
{
}
EDIT 2
I realise that Im looking at this problem in the wrong way (thanks to the answers below who helped me see this) all I care about is that the IO does not happen on ThreadA. This means that it could happen on ThreadB or indeed anyother Thread e.g. a BackgroundWorker. I have decided that creating a new BackgroundWorker within the else portion of the above f statement ensures that the IO is performed in a non-blocking fashion. Im not entirely sure that this is the best solution to my problem, however it appears to work!
Here's one way to do it:
if (System.Threading.Thread.CurrentThread.ManagedThreadId == ThreadB.ManagedThreadId)
...
I don't know enough about .NET's Thread class implementation to know if the comparison above is equivalent to Equals() or not, but in absence of this knowledge, comparing the IDs is a safe bet.
There may be a better (where better = easier, faster, etc.) way to accomplish what you're trying to do, depending on a few things like:
what kind of app (ASP.NET, WinForms, console, etc.) are you building?
why do you want to enforce I/O on only one thread?
what kind of I/O is this? (e.g. writes to one file? network I/O constrained to one socket? etc.)
what are your performance constraints relative to cost of locking, number of concurrent worker threads, etc?
whether the "else" clause in your code needs to be blocking, fire-and-forget, or something more sophisticated
how you want to deal with timeouts, deadlocks, etc.
Adding this info to your question would be helpful, although if yours is a WinForms app and you're talking about user-facing GUI I/O, you can skip the other questions since the scenario is obvious.
Keep in mind that // call performIO so that it is called (invoked?) on ThreadB implementation will vary depending on whether this is WinForms, ASP.NET, console, etc.
If WinForms, check out this CodeProject post for a cool way to handle it. Also see MSDN for how this is usually handled using InvokeRequired.
If Console or generalized server app (no GUI), you'll need to figure out how to let the main thread know that it has work waiting-- and you may want to consider an alternate implementation which has a I/O worker thread or thread pool which just sits around executing queued I/O requests that you queue to it. Or you might want to consider synchronizing your I/O requests (easier) instead of marshalling calls over to one thread (harder).
If ASP.NET, you're probably implementing this in the wrong way. It's usually more effective to use ASP.NET async pages and/or to (per above) synchronize snchronizing to your I/O using lock{} or another synchronization method.
What you are trying to do is the opposite of what the InvokeRequired property of a windows form control does, so if it's a window form application, you could just use the property of your main form:
if (InvokeRequired) {
// running in a separate thread
} else {
// running in the main thread, so needs to send the task to the worker thread
}
The else part of your snippet, Invoking PerformIO on ThreadB is only going to work when ThreadB is the Main thread running a Messageloop.
So maybe you should rethink what you are doing here, it is not a normal construction.
Does your secondary thread do anything else besides the performIO() function? If not, then an easy way to do this is to use a System.Threading.ManualResetEvent. Have the secondary thread sit in a while loop waiting for the event to be set. When the event is signaled, the secondary thread can perform the I/O processing. To signal the event, have the main thread call the Set() method of the event object.
using System.Threading;
static void Main(string[] args)
{
ManualResetEvent processEvent = new ManualResetEvent(false);
Thread thread = new Thread(delegate() {
while (processEvent.WaitOne()) {
performIO();
processEvent.Reset(); // reset for next pass...
}
});
thread.Name = "I/O Processing Thread"; // name the thread
thread.Start();
// Do GUI stuff...
// When time to perform the IO processing, signal the event.
processEvent.Set();
}
Also, as an aside, get into the habit of naming any System.Threading.Thread objects as they are created. When you create the secondary thread, set the thread name via the Name property. This will help you when looking at the Threads window in Debug sessions, and it also allows you to print the thread name to the console or the Output window if the thread identity is ever in doubt.

Invoke() is blocking

From time to time my applications GUI stops redrawing.
There a lot of threads that are firing all kinds of events (like timers or network data ready etc.). Also there are a lot of controls that are subscribing these events. Because of that, all the event handlers play the InvokeRequired/Invoke game.
Now I figured out that when the GUI freezes a lot of threads are waiting for Invoke() to return. Looks like the message pump stopped pumping.
The handlers look like this:
private void MyEventHandler( object sender, EventArgs e ) {
if ( InvokeRequired ) {
Invoke( new EventHandler( MyEventHandler ), sender, e );
return;
}
SetSomeStateVariable();
Invalidate();
}
Any ideas?
Solution: BeginInvoke(). Looks like you should always use BeginInvoke() if you have lots of CrossThread-Events...
Thanks.
Thanks everybody.
EDIT: Looks like BeginInvoke() really solved it. No freezing until now.
Invoke waits until the event is handled in the GUI thread. If you want it to be asynchronous use BeginInvoke()
Deadlock perhaps? Do you make sure that the events are never fired while holding a lock?
Are you able to see this with a debugger attached? If so, make it freeze and then hit the "pause" button - and see what the UI thread is doing.
Note that if you are able to get away with BeginInvoke instead of Invoke, life is a bit easier as it won't block.
Also note that you don't need the "new EventHandler" bit - just
Invoke((EventHandler) MyEventHandler, sender, e);
should be fine.
From watching this question, I can see that you're not going to get any answers that will fix the problem immediately, as most of them require you to debug the event, and it happens so infrequently that this is nearly impossible. So, let me suggest you make some code changes that might help you identify the culprit in the field.
I suggest that you create a static class whose sole purpose is to handle all your Invoke calls. I would suggest that this class has a method that takes a Control, (to call Invoke on) an Action (the method to be invoked), and a description (containing the information you would need to know to identify the method and what it is going to do).
Within the body of this method, I suggest you enqueue this information (method, description) and return immediately.
The queue should be serviced by a single thread, which pops the action/message pair off the queue, records the current time and the Action's description in a pair of properties, and then Invokes() the Action. When the Action returns, the description and time are cleared (your DateTime can be nullable, or set it to DateTime.Max). Note, since all Invokes are marshalled one at a time onto the UI thread, you're not losing anything by servicing the queue by a single thread here.
Now, here's where we get to the point of this. Our Invoking class should have a heartbeat System.Threading.Timer thread. This should NOT be a windows.forms.timer object, as that runs on the UI thread (and would be blocked when the ui is blocked!!!).
The job of this timer is to periodically peek at the time the current Action was Invoked. If DateTime.Now - BeginTime > X, the heartbeat timer will decide that this Action has blocked. The heartbeat timer will LOG (however you log) the DESCRIPTION recorded for that Action. You now have a recording of what was happening at the time your UI locked up and can debug it better.
I know it's not an answer to your problem, but at least by doing this you can get a good idea about what's going on at the time you're blocked.
The most likely answer (deadlock) has already been suggested.
Another way to simulate this behaviour is to reduce the number of pool threads and IO completion ports; you haven't called ThreadPool.SetMaxThreads(...) by any chance?

Categories

Resources