Anytime the beginner asks something like: How to update the GUI from another thread in C#?, the answer is pretty straight:
if (foo.InvokeRequired)
{
foo.BeginInvoke(...)
} else {
...
}
But is it really good to use it? Right after non-GUI thread executes foo.InvokeRequired the state of foo can change. For example, if we close form right after foo.InvokeRequired, but before foo.BeginInvoke, calling foo.BeginInvoke will lead to InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created. This wouldn't happen if we close the form before calling InvokeRequired, because it would be false even when called from non-GUI thread.
Another example: Let's say foo is a TextBox. If you close form, and after that non-GUI thread executes foo.InvokeRequired (which is false, because form is closed) and foo.AppendText it will lead to ObjectDisposedException.
In contrast, in my opinion using WindowsFormsSynchronizationContext is much easier - posting callback by using Post will occur only if thread still exists, and synchronous calls using Send throws InvalidAsynchronousStateException if thread not exists anymore.
Isn't using WindowsFormsSynchronizationContext just easier? Am I missing something? Why should I use InvokeRequired-BeginInvoke pattern if it's not really thread safe? What do you think is better?
WindowsFormsSynchronizationContext works by attaching itself to a special control that is bound to the thread where the context is created.
So
if (foo.InvokeRequired)
{
foo.BeginInvoke(...)
} else {
...
}
Can be replaced with a safer version :
context.Post(delegate
{
if (foo.IsDisposed) return;
...
});
Assuming that context is a WindowsFormsSynchronizationContext created on the same UI thread that foo was.
This version avoid the problem you evoke :
Right after non-GUI thread executes foo.InvokeRequired the state of foo can change. For example, if we close form right after foo.InvokeRequired, but before foo.BeginInvoke, calling foo.BeginInvoke will lead to InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created. This wouldn't happen if we close the form before calling InvokeRequired, because it would be false even when called from non-GUI thread.
Beware of some special cases with WindowsFormsSynchronizationContext.Post if you play with multiple message loops or multiple UI threads :
WindowsFormsSynchronizationContext.Post will execute the delegate only if there still is a message pump on the thread where it was created. If there isn't nothing happens and no exception is raised.Also if another message pump is later attached to the thread (Via a second call to Application.Run for example) the delegate will execute (It's due to the fact that the system maintain a message queue per thread without any knowledge about the fact that someone is pumping message from it or not)
WindowsFormsSynchronizationContext.Send will throw InvalidAsynchronousStateException if the thread it's bound to isn't alive anymore. But if the thread it's bound to is alive and doesn't run a message loop it won't be executed immediately but will still be placed on the message queue and executed if Application.Run is executed again.
None of these cases should execute code unexpectedly if IsDisposed is called on a control that is automatically disposed (Like the main form) as the delegate will immediately exit even if it's executed at an unexpected time.
The dangerous case is calling WindowsFormsSynchronizationContext.Send and considering that the code will be executed: It might not, and there is now way to know if it did anything.
My conclusion would be that WindowsFormsSynchronizationContext is a better solution as long as it's correctly used.
It can create sublte problems in complex cases but common GUI applications with one message loop that live as long as the application itself will always be fine.
Who said InvokeRequired / Control.BeginInvoke is preferred? If you ask me, in most cases it's an anti pattern for the exact reasons you mentioned. The question you linked to has many answers, and some actually do suggest using the synchronization context (including mine).
While it's true that any given control could be disposed by the time you're trying to access it from the posted delegate, that's easily solved using Control.IsDisposed (as your delegate is executing on the UI thread so nothing can dispose controls while it's running):
public partial class MyForm : Form
{
private readonly SynchronizationContext _context;
public MyForm()
{
_context = SynchronizationContext.Current
//...
}
private MethodOnOtherThread()
{
//...
_context.Post(status =>
{
// I think it's enough to check the form's IsDisposed
// But if you want to be extra paranoid you can test someLabel.IsDisposed
if (!IsDisposed) {someLabel.Text = newText;}
},null);
}
}
Related
My program has 2 threads running, thread 1 does something to control a label in a form running on thread 2. So I have to use a delegate and invoke a function in form 1 class to access the label. My code is below and it works perfectly. However, I'm wondering if there is a shorter, better way to do this?
delegate void Change_Status_Call_Back(string status_changed);
public void change_status(string status_changed)
{
if (this.label_status.InvokeRequired)
{
Change_Status_Call_Back obj = new Change_Status_Call_Back(change_status);
this.Invoke(obj, new object[] { status_changed });
}
else
{
this.label_status.Text = status_changed;
}
}
This question is "primarily opinion based". Still, you've touched a pet peeve of mine, so…
You should skip the InvokeRequired check altogether:
public void change_status(string status_changed)
{
this.Invoke((MethodInvoker)(() => this.label_status.Text = status_changed));
}
The framework has to effectively check InvokeRequired anyway, because it's required to support invoking on the UI thread without deadlocking. So the check in your code is redundant. The overhead of always wrapping the method body in a delegate invocation is inconsequential in UI code like this, especially since if you're writing this code, it's probably the case that the method's not going to be called exception when InvokeRequired would be true anyway (i.e. the "fast path" is never taken anyway).
Even better is to use a more modern mechanism for dealing with cross-thread access, such as async/await or the Progress<T> class. Then you never have to write an explicit call to Invoke() at all.
Some time ago, I ranted in more depth here: MSDN’s canonical technique for using Control.Invoke is lame
I would do this:
public void change_status(string status_changed)
{
this.label_status.InvokeSafely(c => c.Text = status_changed);
}
You need this extension method:
public static void InvokeSafely(this Control control, Action<Control> action)
{
if (control.InvokeRequired)
{
control.Invoke((Action)(() => action?.Invoke(control)));
}
else
{
action?.Invoke(control);
}
}
After looking around, I came up with this:
// UPDATE DISPLAY items (using Invoke in case running on BW thread).
IAsyncResult h = BeginInvoke((MethodInvoker)delegate
{
FooButton.Text = temp1;
BarUpdown.Value = temp2;
}
);
EndInvoke(h); // Wait for invoke to complete.
h.AsyncWaitHandle.Close(); // Explicitly close the wait handle.
// (Keeps handle count from growing until GC.)
Details:
I removed if (InvokeRequired) completely. (Discovered from Peter Duniho's answer here.) Invoke() works just fine on the UI thread. In code that runs only on the UI thread, UI actions need no special treatment. In code that runs only on a non-UI thread, wrap all UI actions in an Invoke(). In code that can run on the UI thread -or- a non-UI thread, likewise wrap all UI actions in an Invoke(). Always using Invoke() adds some overhead when running on the UI thread, but: not much overhead (I hope); the actions run less often on the UI thread anyway; and by always using Invoke, you don't have to code the UI actions twice. I'm sold.
I replaced Invoke() with BeginInvoke() .. EndInvoke() .. AsyncWaitHandle.Close(). (Found elsewhere.) Invoke() probably just does BeginInvoke() .. EndInvoke(), so that much is just inline expansion (slightly more object code; slightly faster execution). Adding AsyncWaitHandle.Close() addresses something else: When running on a non-UI thread, Invoke() leaves hundreds of handles that linger until garbage collection. (It's scary to watch Handles count grow in Task Manager.) Using BeginInvoke() .. EndInvoke() leaves lingering handles just the same. (Surprise: Using only BeginInvoke() does not leave the handles; it looks like EndInvoke() is the culprit.) Using AsyncWaitHandle.Close() to explicitly kill the dead handles eliminates the [cosmetic] problem of lingering handles. When running on the UI thread, BeginInvoke() .. EndInvoke() (like Invoke()) leaves no handles, so AsyncWaitHandle.Close() is unnecessary, but I assume it is also not costly.
An IsDisposed test seems safe against race conditions, but I think it is not necessary. I'm worried that BackgroundWorker can Invoke() the operation; while it is pending, a click can trigger a callback on the UI thread that can Close() the form, and then the message loop executes this operation. (Not sure this can happen.)
Problem: (I will update here when something works.) I changed all my UI updates from running on a UI timer kludge to using Invoke() (as above), and now closing the form fails on a race condition about 20% of the time. If a user click stops my background worker, clicking on close after that works fine. BUT, if the user clicks directly on close, that triggers a callback on the UI thread which Close()s the form; that triggers another that flags the background worker to stop; the background worker continues, and it crashes at EndInvoke() saying "Cannot access a disposed object. Object name: 'MainWin'. at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous) ...". Adding if (!this.IsDisposed) {} around EndInvoke() .. AsyncWaitHandle.Close() doesn't fix it.
Option: Go back to using a forms timer: Make the BW write its changes into a dozen global "mailbox" variables. Have the timer do FooButton.Text = nextFooButtonText;, etc. Most such assignments will do almost nothing because setting a form field only updates the display if the value actually changes. (For clarity and to reduce copying objects, initialize the mailbox variables to null, and have the timer do if (nextFooButtonText != null) { FooButton.Text = nextFooButtonText; nextFooButtonText = null; }, etc.) The timer puts a new event on the UI message loop every so many milliseconds, which is more silly grinding than the Invoke()s. Updating the display on a timer callback delays each update by [up to] the timer interval. (Yuck.)
WORKING Option: Use only BeginInvoke(). Why make BW wait for each Invoke to finish? 1) temp1 and temp2 seem passed as references - if they get changed after BeginInvoke(), the new value wins. (But that's not so bad.) 2) temp1 and temp2 can go out of scope. (But aren't they safe against being released until the last reference goes away?) 3) Waiting ensures that BW only has one invoked action pending at a time - if the UI thread blocks for a while, BW can't bury it in events. (But my UI thread can't block, at least not at times when my BW is running.)
Option: Put try .. catch around the EndInvoke(). (Yuck.)
I have seen several other tricks suggested:
•Have Close cancel itself, initiate a timer, and then return so that any lingering Invoke()s finish on the UI thread; shortly after that the timer callback does a real Close (found here; from here).
•Kill the background worker thread.
•Alter Program.cs to shut down differently.
I have a WPF application which used to shutdown via Environment.Exit. Since this caused problems with my automated UI tests, I changed the exiting application to Application.Current.ShutDown.
This works fine, except there is a thread which is waiting to be pulsed (Monitor.Wait), which keeps the process running since it never gets pulsed anymore.
I thought that would be a no brainer to fix, but from the point where my application exits (the Application.Current.ShutDown) it's rather hard to retrieve a reference to the object which holds the waiting thread (in order to force pulse it, so that it can exit).
I tried to google an appropriate answer, but not much luck yet. Is there an "easy way" out of this? Or should I start refactoring already? :)
Some snippets:
Thread is created like this
workerThread = new Thread(Worker) { Name = logName, IsBackground = true};
In the Worker method, Monitor.Wait is called
while ((action = GetNextTask(out task)) == ProductPreparationAction.None)
{
Monitor.Wait(preparationTasks);
}
Nevermind my comment. Start refactoring :).
First of all, there should be a way for the while loop to end when before the app stops. Perhaps you can use and propagate a CancellationToken all the way down to the Worker method.
If you want to keep your loose coupling, you should be able to pulse by creating an event in the class that calls Application.Current.ShutDown and by subscribing to it in the class where the Worker method is (and call Pulse in the event handler).
If you do this, then you can store the CancellationToken in this class and flag it when the event is received.
That event should be raised before calling Application.Current.ShutDown.
Hi,
I have the following code that is runned during Application.Exit :
if (InvokeRequired && this.IsHandleCreated)
{
this.Invoke(new Action(() => EndUpdate(Caller)));
return;
}
This throws the exception : Invoke or BeginInvoke cannot be called on a control until the window handle has been created but only when application is exeting.
The strange part is that when debugger breaks for the error I can see that both InvokeRequired and IsHandledCreated is set to false so im not sure how it manage to get to the internal code(this.Invoke)?
In this case I just want to close the application without any exceptions.
Checking conditions that way is not thread-safe.
Firstly, you can hit the race condition when threads are switched between if operator and call to Invoke. In other cases i would recommend you put some synchronization here, but it's impossible to get inside framework code.
Also, Invoke puts query into the UI message queue and then UI thread extracts it from the queue and executes. Meanwhile, Invoke waits till UI thread finish executing this query using Form.Handle.
So make sure you don't have calls to Form.Close() inside EndUpdate method, that can lead to exception while waiting.
I just recommend you to put EndUpdate() call inside Form.OnClosing() override. That would be thread safe and Handle is guaranteed to exist.
I created a multithreading C# COM-Assembly, I used it from VB6.
The C#-COM can fire events from multiple threads, I created an invisible From-object and use this to synchronize all events before raise them.
if (myForm.InvokeRequired() )
{
delOnMessage myDelegate = new delOnMessage(Message_received);
myForm.Invoke(myDelegate, new object[] { null, null });
}
else
{
RaiseMyEvent();
}
But if the VB6-Code is inside of an event handler and calls some methods of the COM-Object, this can produce a new event.
Private Sub m_SomeClass_SomeEvent(obj As Variant)
COMobject.SendAnAnswer() ' This produces a new event
End Sub
In that case a part of the event-system stops working, suprisingly the Main VB6 Applikation still works.
EDIT: More detailed
If the C#-COM received a Message (from CAN-Bus-Thread) it creates an event, in some cases the VB6 calls a C#-COM method which creates an event, this event is reached the VB6 too.
But then the CAN-Bus-Thread seems to be blocked, as no more messages are received (till program restart).
But other events can occur.
The CAN-Bus-Thread is an endless loop to receive a message and fire an event.
I have two questions:
Is my way of synchronizing correct?
Is it possible without modifying the VB6-code to get it working?
I created an invisible From-object
That sounds like trouble. Using InvokeRequired is a dangerous anti-pattern. It is especially lethal with VB6, its runtime has badly broken thread handling. You know that the code is being called from a worker thread, use InvokeRequired only to verify that the form you use to synchronize is in the proper state to do so correctly:
if (!myForm.InvokeRequired()) {
throw new InvalidOperationException("Synchronization window not created");
}
delOnMessage myDelegate = new delOnMessage(FireMessageReceivedEvent);
myForm.BeginInvoke(myDelegate, new object[] { null, null });
Odds are good that this exception will throw, creating an invisible form is not that easy. You can force the form's Handle property to be created by reading its Handle property. Or by overriding its SetVisibleCore() method to keep the form invisible:
protected override void SetVisibleCore(bool value) {
if (!this.IsHandleCreated) {
this.CreateHandle();
value = false;
}
base.SetVisibleCore(value);
}
It is however very important that you call this form's Show() method on the main thread. It still won't work correctly if you create the form in your worker thread. There's no easy way to check for this in your code. Use the debugger and the Debug + Windows + Threads window to verify this.
Last but not least, do favor BeginInvoke() instead of Invoke(). This has much smaller odds of creating deadlock. This can cause problems by itself however, your worker thread may need to be throttled to prevent it flooding the main thread with invoke requests.
Depending on the nature of the event, it may be sufficient simply to switch from Invoke to BeginInvoke, so that it is offloaded to the message-queue (without blocking, so no deadlock). It is convenient that Control.BeginInvoke (unlike Delegate.BeginInvoke) does not require you to call EndInvoke, so you can use this in a fire-and-forget way.
I might be tempted to cut out some extra work, though:
myForm.BeginInvoke((MethodInvoker)RaiseMyEvent);
(i.e. jump direct to RaiseMyEvent)
The Scenario
I have a windows forms application containing a MAINFORM with a listbox on it. The MAINFORM also has a THREAD POOL that creates new threads and fires them off to do lots of different bits of processing. Whilst each of these different worker threads is doing its job, I want to report this progress back to my MAINFORM, however, I can't because it requires Cross-Thread communication.
Progress
So far all of the tutorials etc. that I have seen relating to this topic involve custom(ish) threading implementations, whereas I literally have a fairly basic(ish) standard THREAD POOL implementation. Since I don't want to really modify any of my code (since the application runs like a beast with no quarms) - I'm after some advice as to how I can go about doing this cross-thread communication. ALTERNATIVELY - How to implement a different "LOGTOSCREEN" method altogether (obviously still bearing in mind the cross-thread communication thing).
WARNING:
I use this website at work, where we are locked down to IE6 only, and the javascript thus fails, meaning I cannot click accept on any answers during work, and thus my acceptance rate is low. I can't do anything about it I'm afraid, sorry.
EDIT:
I DO NOT HAVE INSTALL RIGHTS ON MY COMPUTER AT WORK.
I do have firefox but the proxy at work fails when using this site on firefox.
And no, funnily enough, I don't have the internet at home, I literally just moved to this city and the flat is a new build, so the address hasn't been registered with the post office, and thus the phone company cannot find the address on their system till they send a surveyor out, smarty pants.
FURTHER EDIT:
I DO NOT WANT TO CHANGE MY THREADING IMPLEMENTATION. AT ALL! - Accept to enable cross-thread communication....why would a backgroundworker help here!?
CODE RELATED EDIT:
Does it make a difference that when my THREAD POOL executes the new threads, it creates a new instance of a class and calls the entire thing on that new thread........i.e. your code example doesn't quite fit....i think?
Use the BackgroundWorker class in .NET and use the ProgressChanged and RunWorkerCompleted events to communicate back to your UI thread
Edit:
Sounds like you don't like BackgroundWorker, or just don't want to refactor. In that case, you have to check the InvokeRequired property on your form or one of your controls and if it is true, then you have to call Control.Invoke to force your UI update logic to occur on your main thread.
here is an example:
private void MyThreadFunction()
{
if (!InvokeRequired)
{
myLabel.Text = "You pushed the button!";
}
else
{
Invoke(new ThreadStart(MyThreadFunction));
}
}
You can use any delegate type to pass to Invoke, because it takes optional parameters that can be passed to your delegate when it is invoked on the main thread.
You could do something like this:
class MyForm : Form
{
private Label label = new Label();
private void DoWork()
{
// Do work ... Not in UI thread
// Update label... In UI thread
this.Invoke(new MethodInvoker(() => label.Text = "New Text!"));
}
}
The DoWork method it's the one running in your worker threads. You could check if an invoke is required using InvokeRequired property, but the assumption is that your code is running on worker threads so the invoke will always be required.
You can do this using delegate object.
So you would create a callback method in your MAIN form and let your CHILD forms call this method using delegates when they are done processing.
Try using Control.BeginInvoke to queue your update to the UI on the UI thread.