SynchronizingObject vs. Invoke - c#

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)

Related

What is the best way to invoke a function?

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.

System.Windows.Forms.Timer not firing

I want to use a System.Windows.Forms.Timer to ensure that an event fires on the UI thread of an excel addin I'm creating. I construct the timer as follows:
private System.Windows.Forms.Timer _timer;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
Debug.WriteLine("ThisAddIn_Startup:" + Thread.CurrentThread.ManagedThreadId);
_timer = new System.Windows.Forms.Timer();
_timer.Tick += new EventHandler(TimerEventHandler);
_timer.Interval = 500;
}
The timer is fired by a COM event from a library I am using:
private void OnEvent()
{
_timer.Start();
}
I then expect the _timer to call the following method when it ticks:
public void TimerEventHandler(object sender, EventArgs args)
{
_timer.Stop();
Debug.WriteLine("Tick: " + Thread.CurrentThread.ManagedThreadId);
}
As I understand, when I create the timer in the Addin thread, even though it is started from another thread (COM event in this case), it should fire on the thread that it was created on, i.e. the addin thread. However, this doesn't happen.
I have implemented this exact mechanism in an RTDServer I wrote in the past (as outlined by Kenny Kerr) and it works as expected but the _timer in this scenario never ticks.
I have also read other SO articles that point to the same behavior and can't figure out what is different about my addin setup?
EDIT:
The OnEvent() method is fired.
The winforms timer is a control and must be used by placing it on a form. You never add it to a control-collection, so I would not expect it to work properly. The documentation says the following
Implements a timer that raises an event at user-defined intervals. This timer is optimized for use in Windows Forms applications and must be used in a window.
Therefore, I would suggest that you use an instance of the System.Timers.Timer class. This class can be used anywhere.
Note that the Tick-event you use above, is called by another name in the System.Timer.Timer class, namely the Elapsed-event.
I initially meant to post this as comment, but it turned to be too long.
Firstly, your thread structure is a bit confusing to me, the way you described it. Put Debug.WriteLine("OnEvent:" + Thread.CurrentThread.ManagedThreadId) inside OnEvent and let us know all thread IDs you see from your debug output.
That said, the rules are:
You should create WinForms' Timer object on an STA thread, and the thread should be configured as STA before it starts.
This thread may or may not be the main UI thread (where your main form was created), but it still should execute a message loop (with Application.Run) for timer events to fire. There are other ways of pumping messages, but generally you do not control them from .NET code.
You should handle the events sourced by WinForms' Timer on the same thread it was created. You can then 'forward' these events to another thread context if you like (using SynchronizationContext Send or Post) but I can't think of any reasons for such complexity.
The answer by #Maarten actually suggests the right way of doing it, in my opinion.
I don't yet understand why the Forms.Timer doesn't operate as expected but the following excellent article explains in detail how to marshal work onto the UI thread: http://www.codeproject.com/Articles/31971/Understanding-SynchronizationContext-Part-I

Prevent C# events to VB6 code to create a dead lock

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)

Kill event thread

I have a timer event that fires every second. Sometimes when I exit the program (in the VS debugger), it tells me that the event thread is trying to access an object that no longer exists (because the main thread is over). I tried disabling the event before I exit (UpdateTime.aTimer.Enabled = false;). This cut down the number of times this problem occurs, but it still happens sometimes because the event fires before I can disable it.
Is this a serious problem? Will is haunt me if I don't deal with it?
If yes to the above, how do I kill it?
I ask the second question because I have no reference to the event thread, so I don't know how I can tell it to stop or wait for it to finish.
EDIT: More context. This is a Winform.
Also, I'm not explicitly creating a thread. It's my understanding that a thread is automatically created to handle events.
Creating the timer:
public static void Update(){
System.Timers.Timer aTimer = new System.Timers.Timer(1000);
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Enabled = true;
}
Event handler:
private static void OnTimedEvent(object source,ElapsedEventArgs e) {
Form1obj.updateLabel(String.Format("{0}", DateTime.Now.Second),Label1);
}
Closing program handler:
private void Form1_FormClosing(object sender,FormClosingEventArgs e) {
aTimer.Enabled = false;
}
Serious Problem? Probably not, but I don't think a problem needs to be serious to need to be fixed. Warnings should be treated as errors in compilation, for example. In addition, if this is an app sent to clients, showing ugly errors on shutdown is not very professional.
How to solve this depends on how you are setting up the threads ("event thread" does not give enough info about the mechanics). One easy method might be to stall the main thread for a bit when the application shuts down until the threads all return. You have to also stop issuing new threads during this time.
Another possible solution would be to handle how the threads are created so you can shut down the process that fires them. Concepts like ThreadPool come to mind. Also ensuring threads are background threads, explicitly, can help in some situations.
The short answer is nobody will be able to give you a firm "this will fix your issue" answer without some context of what you are doing in your code.
ADDED:
There are a couple of "quick, down and dirty" ways to handle this. Don't have time for full analysis, so see if they work.
Just cure the error by waiting
Add a counter and wait until incremented down
The first thing I would consider is adding a safety net to not update the label when in a shutdown condition. That is regardless of anything else, as that is where your errors are firing. I don't think "main thread is not present" is the core of the issue, but rather this line:
Form1obj.updateLabel(String.Format("{0}", DateTime.Now.Second),Label1);
How can you update something that no longer exists? Yes, it is on the main thread, so technically ...
A simple wait would be something like:
private void Form1_FormClosing(object sender,FormClosingEventArgs e)
{
aTimer.Enabled = false;
Thread.Sleep(5000);
}
Hiding the form is also not a bad idea, so the user does not see this?
If you want to use a more "COM like approach", you can add a counter. Increment on Update() (when the event is fired) and decrement on OnTimedEvent(). Make sure you lock the counter when changing it so you do not end up with two threads changing it at the same millisecond. You can then wait until the counter is 0 to finish form close or application unload.
Once again, these are quick, down and dirty, approaches, but they can save you from the error. I am sure someone with more time can come up with a more elegant solution.
You can close the window as suggested in MSDN - when you set the timer to be disabled during shutdown processing, set a flag that your Elapsed event handler can check to know that no more work is needed.
Elapsed events can occur after the
Dispose or Stop method has been called
or after the Enabled property has been
set to false, because the signal to
raise the Elapsed event is always
queued for execution on a thread pool
thread. One way to resolve this race
condition
is to set a flag that tells the event
handler for the Elapsed event to
ignore subsequent events.
Its hard to give a general awnser to the question if its serious or not, it depends entiry on what the timer is doing. what kind of timer is it? a system.Threading one or one of the UI timers?
If possible try and refactor your code so that you can tell the timer to stop firing, if only for the reason not to confuse the users with an error message. it could be as simple as sharing a variable or (preferably) using a CancellationToken

C# Thread Pool Cross-Thread Communication

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.

Categories

Resources