C# BackgroundWorker Cancellation with Helper Function - c#

Normally, when I want to cancel a backgroundWorker in C# I will do something like this:
while (backgroundWorker1.IsBusy)
{
backgroundWorker1.CancelAsync();
autoResetEvent1.WaitOne(BGW_CANCEL_TIMEOUT);
}
In one application there are a number of backgroundWorkers. Is it valid to use a helper-function to cancel the backgroundWorkers, like so?
CancelBackgroundWorker(BackgroundWorker bgw, AutoResetEvent are)
{
while (bgw.IsBusy)
{
bgw.CancelAsync();
are.WaitOne(BGW_CANCEL_TIMEOUT);
}
}
My concern is that instead of passing the objects in question into the function, copies are made, thereby defeating the purpose of having the function. The main purpose of having the function is to reduce code space and make the application code more readable/maintainable.

No, this isn't okay. It causes deadlock when the BGW has a RunWorkerCompleted event handler. That handler cannot run until the main thread goes idle and re-enters the message loop. The IsBusy property will stay True until that event handler completes.
You have a time-out on the WaitOne call so at least your program won't hang completely. But when WaitOne() returns, the BGW is not yet completed, the RWC event handler hasn't run yet. The only practical alternative is for the RWC event handler to do whatever needs done when the cancellation is complete.

Your code is wrong.
Calling CancelAsync merely sets the CancellationPending flag on the BackgroundWorker to true. Your code in the DowWork event is expected to periodically check this flag and stop if the flag is true.
Calling CancelAsync many times will not do any good, and there shouldn't be any reason to freeze the UI thread until it actually cancels.

Related

AutoResetEvent.WaitOne() cause deadlock

I'm writing a application with a critical region.
And I decide to use AutoResetEvent to achieve mutual exclusion.
Here's the code
public class MyViewModel
{
private AutoResetEvent lock = new AutoResetEvent(true);
private aync Task CriticalRegion()
{
Dosomething();
}
public async Task Button_Click()
{
Debug.WriteLine("Entering Button_Click");
lock.WaitOne();
try
{
await CriticalRegion();
}
finally
{
lock.Set();
Debug.WriteLine("Leaving Button_Click");
}
}
}
I have a button whose click event calls the Button_Click() method
It works normally. But, if I'm quick enough to click the button for another time before the first call to Button_Click() completes, the whole app stops responding.
In the Debug window I find something like this
Entering Button_Click
Entering Button_Click
Looks like the method never completes.
I struggled a bit and find that if I change lock.WaitOne(); to
if (!sync.WaitOne(TimeSpan.FromSeconds(1)))
{
return;
}
In this case my app is able to avoid the deadlock,but I don't know why it works.
I only know about the IPC from my OS course and the async and await pattern in C#, and I'm not so familiar with the thread in .Net world.
I really want to understand what's really going on behind the scenes.
Thanks for any replys ;)
You have a deadlock because WaitOne is blocking the main thread (button click handler is executed on the main thread), while you haven't called ConfigureAwait(false) when calling await, which means that it tries to run the code which is after await on the main thread, even if it's blocked, which would causes a deadlock.
I suggest reading this post for a thorougher explanation of the dead lock situation.
For your code, I would suggest putting the lock deeper, probably within the async Task, and trying to use a more suitable pattern for locking, preferably, the lock statement, because using Event objects is awkward for mutual exclusion, as Hans stated in the comment.
AutoResetEvent.WaitOne() will block infinitely until you call AutoResetEvent.Set(), which you never seem to do except for after the WaitOne() call.
Quoting the AutoResetEvent.WaitOne() documentation:
Blocks the current thread until the current WaitHandle receives a signal.

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.

What happens if a new Entry is written to the Event Log while the application is inside the handler for a previous entry being written?

My application needs to review all new application Event Log entries as they come in.
private void eventLog_Application_EntryWritten(object sender, EntryWrittenEventArgs e)
{
// Process e.Entry
}
What I would like to know is what happens if another Entry is written to the EventLog while a previous Entry is being handled?
The documentation for EventLog.EntryWritten Event provides an example of handling an entry written event which uses threading (which is why I am asking the question).
In this example they use System.Threading and call the WaitOne() and Set() methods on the AutoResetEvent class, however I'm not sure precisely what this code is intended to achieve.
The documentation states that - WaitOne() "blocks the current thread until the current WaitHandle receives a signal", and that Set() "sets the state of the event to signaled, allowing one or more waiting threads to proceed". I'm not sure what the threading portion of this example is intended to demonstrate, and how this relates to how (or if) it needs to be applied in practice.
It appears that WaitOne() blocks the thread immediately after the entry has been written, until it has been handled, where it is then set to signalled (using Set()), before allowing the thread to proceed. Is this the one and only thread for the application?
Most importantly, when my application is not responsible for writing the the events which need to be read from the EventLog, how should this principle be applied? (If, indeed, it needs to be applied.)
What does happen if a new Entry is written while the application is inside the handler?
Nothing dramatic happens, it is serialized by the framework. The underlying winapi function that triggers the EventWritten event is NotifyChangeEventLog(). The .NET Framework uses the threadpool to watch for the event to get signaled with ThreadPool.RegisterWaitForSingleObject(). You can see it being used here.
Which is your cue to why the MSDN sample uses ARE (AutoResetEvent). The event handler runs on that threadpool thread, exactly when that happens is unpredictable. The sample uses a console mode app, without that ARE it would immediately terminate. With the ARE, it displays one notification and quits. Not actually that useful of course, I would personally just have used Console.ReadLine() in the sample so it just keeps running and continues to display info until you press the Enter key.
You don't need this if you use a service or a GUI app, something that's going to run for a long time until the user explicitly closes it. Note the EventLog.SynchronizingObject property, makes it easy to not have to deal with the threadpool thread in a Winforms app.
The example is not really helping to explain the way the AutoResetEvent works in a multi-threaded scenario, so I'll try to explain how I understand it to work.
The AutoResetEvent signal static variable, is instantiated as a new AutoResetEvent with its signaled state set to false, or "non-signaled", meaning that calling signal.WaitOne() will cause the thread that called WaitOne to wait at that point, until the signal variable is "set" by calling the signal.Set() method.
I found an explanation of AutoResetEvent that describes it very well in understandable real-world terms, which also included this excellent example below.
http://www.albahari.com/threading/part2.aspx#_AutoResetEvent
AutoResetEvent
An AutoResetEvent is like a ticket turnstile: inserting a ticket lets
exactly one person through. The “auto” in the class’s name refers to
the fact that an open turnstile automatically closes or “resets” after
someone steps through. A thread waits, or blocks, at the turnstile by
calling WaitOne (wait at this “one” turnstile until it opens), and a
ticket is inserted by calling the Set method. If a number of threads
call WaitOne, a queue builds up behind the turnstile. (As with locks,
the fairness of the queue can sometimes be violated due to nuances in
the operating system). A ticket can come from any thread; in other
words, any (unblocked) thread with access to the AutoResetEvent object
can call Set on it to release one blocked thread.
class BasicWaitHandle
{
static EventWaitHandle _waitHandle = new AutoResetEvent (false);
static void Main()
{
new Thread (Waiter).Start();
Thread.Sleep (1000); // Pause for a second...
_waitHandle.Set(); // Wake up the Waiter.
}
static void Waiter()
{
Console.WriteLine ("Waiting...");
_waitHandle.WaitOne(); // Wait for notification
Console.WriteLine ("Notified");
}
}
According to https://msdn.microsoft.com/en-us/library/0680sfkd.aspx the eventlog components are not thread-safe and that code is there to prevent unexpected behaviour in simultaneous interactions.
If multiple threads are executing these lines simultaneously, if is possible for one thread to change the EventLog.Source Property of the event log, and for another thread to write a message, after that property had been changed.

Thread "hanging" on Monitor.Wait after Application.Current.ShutDown()

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.

BackgroundWorker - CancellationPending changing to false in RunWorkerCompleted. Why?

After canceling the BackGroundWorker, in the DoWork, the CancellationPending is true but when he comes to the RunWorkerCompleted, the CancellationPending is false. I dont know what did I do wrong?
static BackgroundWorker b1;
static void Main(string[] args)
{
b1=new BackgroundWorker();
b1.DoWork += new DoWorkEventHandler(work1);
b1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(completed);
b1.WorkerSupportsCancellation = true;
b1.RunWorkerAsync("Hellow");
Console.ReadLine();
}
private static void completed(object sender, RunWorkerCompletedEventArgs e)
{
if (((BackgroundWorker)sender).CancellationPending)
Console.WriteLine("Canceled!");
else
Console.WriteLine("Result:" + e.Result);//it goes here every time
}
private static void work1(object sender, DoWorkEventArgs e)
{
((BackgroundWorker)sender).CancelAsync();
if (((BackgroundWorker)sender).CancellationPending)
{
e.Cancel = true;
}
}
By the way, How can I add an error that occur in the DoWork to the RunWorkerCompletedEventArgs.Error for shoing it up to the user?
Yes, the BackgroundWorker class sets the CancellationPending property to false before raising the RunWorkerCompleted event. Whether or not the worker was actually cancelled.
This is quite intentional, it stops you from falling into a nasty trap that's always around when you use threads. Code that uses threads often misbehaves randomly and unpredictably due to a kind of bug called "threading race". It is a very common kind of bug and dastardly difficult to debug.
What can easily go wrong in your intended approach if BGW didn't do this is that you'll assume that the worker got cancelled when you see CancellationPending set to true. But that's an illusion, you cannot tell the difference between it being cancelled and it completing normally. The corner case is you calling CancelAsync() a microsecond before the worker completes. The worker never has a chance to even see the CancellationPending flag set to true, it was busy finishing the last bits of the DoWork event handler method. That's a threading race, the worker raced ahead of your call and completed normally.
The proper hand-shake that avoids this bug is your worker setting e.Cancel to true when it sees the CancellationPending property set to true. And of course stopping what's its doing. Now it is reliable, the e.Cancelled property in the RunWorkerCompleted event handler is a copy of e.Cancel. So your code can now reliably tell you whether or not the worker saw the cancel request.
I believe the CancellationPending property is for use during the background operation (in your work1 method). It will tell the background worker that you have requested the background operation be canceled. Once the RunWorkerCompleted event is called, the background worker has done the work to cancel the request, and therefore the cancellation is no longer pending.
EDIT: the RunWorkerCompletedEventArgs has a Cancelled property that will tell you if the background operation was cancelled.
If you throw an exception from the DoWork method (work1 in your case), it should be caught by the BackgroundWorker and populate the Error property of the RunWorkerCompletedEventArgs.

Categories

Resources