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)
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.
Given
Action closeLoadingAction = new Action(() =>
{
loadingForm.Close();
#region - may need to put into second Action
panelOnMainForm.Controls.AddRange(physdocControls.ToList<Control>().ToArray());
if (Handle != IntPtr.Zero)
User32DLL.SetForegroundWindow(this.Handle);//Handle is a property of the mainForm.
#endregion
});
Sometimes I get handle not created exceptions even though I check the Invoke required.
if(loadingForm.InvokeRequired)
loadingForm.Invoke(closeLoadingAction);
else
closeLoadingAction();
The loading form runs on the same thread as the main form. The code you see above runs in a seperate thread. I suspect that I need another check for invoke against the main form. Do I need a second check or is what I have already safe?
The code you see above runs in a seperate thread
Using InvokeRequired like this when you know that the code runs on another thread is a bad anti-pattern. You can do much more useful things with it. Like:
if (!loadingForm.InvokeRequired) {
throw new InvalidOperationException("Threading race detected");
}
loadingForm.Invoke(closeLoadingAction);
Or the more practical one if you meant to start the loading thread before the loading form's Load event fired:
while (!loadingForm.InvokeRequired) Thread.Sleep(50);
loadingForm.Invoke(closeLoadingAction);
Or just do it the right way and have the form's Load event start the thread.
You should only get those "handle not created" exceptions if the form hasn't been shown or was closed before you try to Invoke the delegate. Not enough code to determine if that's the case though, so if I were in your shoes I'd try to determine if the loading form's (since that's the invoker) Closed event is being called before the method actually gets invoked.
Because both forms are on the same thread, you should be safe just checking the loading form's InvokeRequired property. Though in general, if you're going to operate on the main form, you should check that form's InvokeRequired property. Likewise, if you're going to operate on the loading form (like calling Close above), you should check the loading form's InvokeRequired property. Above you're changing panelOnMainForm so I'd check that to be totally safe, but I don't believe it's necessary.
Sounds like a race between the handle being created for loadingForm and the call to loadingForm.Close().
One way around this is to start the thread that has your .Invoke/.Close code when the loadingForm.HandleCreated event fires.
private void loadingForm_HandleCreated(object sender, EventArgs e)
{
var t = new Thread(DoLoadingStuff);
t.Start();
}
private void DoLoadingStuff()
{
// ...
if(loadingForm.InvokeRequired)
loadingForm.Invoke(closeLoadingAction);
else
closeLoadingAction();
}
public void RefreshData()
{
// this is called on UI thread
List<ds> dataSource;
GetDsDelegate caller = GetDs;
caller.BeginInvoke(out dataSource, RefreshCallback, null);
}
private void RefreshCallback(IAsyncResult ar)
{
// this is called on worker thread
try
{
var result = (AsyncResult)ar;
var caller = (GetDsDelegate)result.AsyncDelegate;
List<ds> dataSource;
var success = caller.EndInvoke(out dataSource, ar);
if (success)
{
BeginInvoke(new Action<List<ds>>(SetGridDataSource), dataSource);
}
}
catch
{
// NOTE: It's possible for this form to close after RefreshData is called
// but before GetDs returns thus the SetGridDataSource method no longer exists.
// Not catching this error causes the entire application to terminate.
}
private void SetGridDataSource(List<ds> dataSource)
{
// this is called on UI thread
dataGrid.DataSource = dataSource;
}
RefreshData, RefreshCallback, and SetGridDataSource are all methods of a windows Form class. Calling RefreshData invokes the external method GetDs using the GetDsDelegate delegate. When GetDs completes, it calls RefreshCallback (now on a separate thread). Finally, SetGridDataSource is invoked to complete the update.
All this works fine unless GetDs is delayed and the form closes. Then when GetDs completes and calls RefreshCallback, SetGridDataSource no longer exists.
Is there a better way of handling this condition other then the shown try/catch block? I’d prefer to prevent the error rather than ignore it. Is there a better pattern to use?
EDIT
As I look that the error, it’s obvious to change if (success) to if (success && IsHandleCreated) to prevent it, but it still seems like I’m doing something wrong, or at least awkward. I could also replace the second BeginInvoke with just Invoke so EndInvoke is unnecessary. I like the idea of moving the logic away from the form, but I don't see how the result would change. I would think a BackgroundWorker would also have the same issue; that being the callback is no longer accessible. I suppose an event could be raised with the result, but that seems a little abstract. Could you please elaborate a little more or provide an example.
The method does exist. The fact the form was closed does not change the class or its methods. If you post the exact exception you're getting, it can help someone offer a more accurate help.
I'm guessing you got an ObjectDisposedException when you tried to do something on the form or one of its control after it has been closed.
If that's the case you just have to enhance your logic and check if the form has been closed or disposed before calling SetGridDataSource.
That said, there seem to be some issues with your design.
You're calling SetGridDataSource from the thread pool, but it probably should called from the UI thread.
Your'e not chaining the asynchronous calls correctly. And specifically, you're not calling EndInvoke on the second BeginInvoke.
A nice way that can help you get the threading right is to use something like the BackgroundWorker instead of chaining BeginInvoke calls.
Consider moving the business logic (including the threading and asynchronity logic) away from the UI layer and the form.
It's a very bad idea to do a catch without an exception type, and handle any thrown exception by ignoring it without rethrowing.
By the way, instead of doing this:
BeginInvoke(new Action<List<ds>>(SetGridDataSource), dataSource);
you can do the following, which I think is more readable:
BeginInvoke(SetGridDataSource, dataSource);
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);
}
}
In my form's class, I've added a method to "fade" it out. This makes use of System.Timers.Timer and the Elapsed event uses a delegate to change the form's opacity. This was the code:
public void FadeOut()
{
// Timer for transition
Timer fade = new Timer();
// Transition code
fade.Elapsed += delegate
{
this.Opacity += 0.05;
if (this.Opacity >= .95)
{
this.Opacity = 1;
fade.Enabled = false;
fade.Dispose();
}
};
fade.Interval = 100;
fade.Enabled = true;
}
This caused a "Cross-thread operation not valid" error, which is a common hurdle I see. So I looked around for solutions and the first ones to come up involved using .BeginInvoke and blocks of code to keep the call to the same thread as the control. But I found this looked really bulky, so I kept looking and then discovered the SynchronizingObject property of System.Timers.Timer. This seems better because it only needed one extra line of code:
// Timer for transition
Timer fade = new Timer();
fade.SynchronizingObject = this;
The code runs fine now. But I'm really confused, how come a lot of solutions are suggesting the use of BeginInvoke/Invoke when all that's needed is to set SynchronizingObject to the form control?
Mostly because it is pointless to use the property. Yes, it ensures that the Elapsed event handler runs on the UI thread. But now it just does the same thing as a System.Windows.Forms.Timer.
Not quite though, it is worse. Because it doesn't guarantee that Elapsed won't be called after you disable it. Disabling it doesn't flush any pending invokes nor TP threads that aren't ready to run yet. There could be hundreds if the Interval is small compared to the amount of work done by the handler.
You absolutely want a System.Windows.Forms.Timer here. You are not doing any useful work on the threadpool thread.
I'm not sure, but I believe that the Timer will internally use Invoke or BeginInvoke as well on the SynchronizingObject property.
Let us say that this property just gives some abstraction to the developer; to make his life easier.
My guess was indeed correct, this is what Reflector tells us about the MyTimerCallback private member method of System.Timers.Timer:
ElapsedEventHandler onIntervalElapsed = this.onIntervalElapsed;
if (onIntervalElapsed != null)
{
if ((this.SynchronizingObject != null) && this.SynchronizingObject.InvokeRequired)
{
this.SynchronizingObject.BeginInvoke(onIntervalElapsed, new object[] { this, e });
}
else
{
onIntervalElapsed(this, e);
}
}
Why don't you use the WinForms timer? This is based on window messages and will always run in the UI thread; since you want to perform updates where the UI thread needs to pump messages anyways this may be a better solution (no synchronization/blocking required).
Timer solutions like this are really a bit of a hack.
You'd be better off writing a proper asynchronous thread and doing the callback either with
BeginInvoke or SynchronizationContext.
As you rightly observe, it's far from a one-liner, but multi-tasking, done properly, never is.
The point is the SCOPE of code. The whole event handler? or just the UI changing code.
timer.SynchronizingObject make the event handler to be called on the thread of given object. If you set this to 'this' in 'Form1' class, This means that all of your code for processing timer event is run by that same thread of 'Form1' instance even though you created a thread based timer. So this does NOTHING. SAME as windows form timer.
The reason you want to do this is because you want to access UI controls and make some changes in Form1, but the whole UI hangs if you use windows form timer. Because they all get executed on the same thread.
To avoid this, you use a threading based timer. Your event handler is called on another thread that comes from some system thread pool. This solves the problem of hanging UI. However, this brings up another problem. Cross-thread accessing UI controls exception. On some versions of Visual Studio, you can disable this checking on debug builds. But there is no way you can just bypass this checking on release builds. This thread checking is just by design to safeguard from crashes caused by multi-threading. THEN you need to use all those invoke and delegation stuff.
The important part here is that it is the only few lines of code that is redirected to be run on the Form1 thread. Not the whole event handler. Most of the event handling code is run on another thread. And that includes code like doing something on network or disk.
This makes the DIFFERENCE.
BUT, all these apply to windows form apps only. For WPF, just use dispatcher timer. (This is why you cannot find Windows.Threading in WinForm because you can't used dispatcher timer in WinForm, but available in WPF)