How to "Kill" Background Worker Completely

How to kill a BackgroundWorker process when it is waiting for an external event

EDIT: To force the SCardGetStatusChange function to cancel, use SCardCancel: https://msdn.microsoft.com/en-us/library/windows/desktop/aa379470(v=vs.85).aspx

How to stop BackgroundWorker correctly

CancelAsync doesn't actually abort your thread or anything like that. It sends a message to the worker thread that work should be cancelled via BackgroundWorker.CancellationPending. Your DoWork delegate that is being run in the background must periodically check this property and handle the cancellation itself.

The tricky part is that your DoWork delegate is probably blocking, meaning that the work you do on your DataSource must complete before you can do anything else (like check for CancellationPending). You may need to move your actual work to yet another async delegate (or maybe better yet, submit the work to the ThreadPool), and have your main worker thread poll until this inner worker thread triggers a wait state, OR it detects CancellationPending.

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.cancelasync.aspx

http://www.codeproject.com/KB/cpp/BackgroundWorker_Threads.aspx

Stopping background worker

Same answer as Marc Gravell but you don't seem to follow.

Are you setting e.cancel = true?

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;

for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}

How to cancel a backgroundworker with multiple methods in c# optimal?

When working with a background worker, really the only choice you have is to pepper your code with checks to see if the operation has been cancelled.

How you implement this is entirely up to you, but I'd say you want to check at the start of every potentially-time-consuming operation, e.g. a database query or file system operation, and definitely at the beginning of every loop.

Now, as you've already noticed, it gets trickier when you have multiple methods involved. In that case, storing your worker in a class-level field is probably appropriate so that you can simply check its cancellation status from every method wherever applicable.

One useful approach would be to utilize your own custom Exception class. You could wrap the code in the top-level method within a try-catch block, and then whenever you find out that the background worker has been cancelled somewhere deeper within the call stack, you could just throw an instance of your exception which would be handled by the catch block.

Here's a simple example I worked up.

class CancellationException : Exception
{
public object State { get; private set; }

public CancellationException(object state)
{
this.State = state;
}
}

private void DoSomething()
{
if (_worker.CancellationPending)
{
throw new CancellationException("cancelled from blah blah");
}
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
DoSomething();
}
catch (CancellationException ce)
{
e.Cancel = true;
}
}

Note that the State property in the exception could be used to determine where in your process the cancellation hit so that you can clean up resources, etc.

Stop a background worker

It appears that you have looked all over the place except for the one obvious place that you should have looked first, i.e. the Help documentation. The doco for the BackgroundWorker.CancelAsync method has this to say:

CancelAsync submits a request to terminate the pending background
operation and sets the CancellationPending property to true.

When you call CancelAsync, your worker method has an opportunity to
stop its execution and exit. The worker code should periodically check
the CancellationPending property to see if it has been set to true.

Where in your code are you doing as that instructs? Nowhere, so you're obviously not doing it how it should work.

Calling CancelAsync only requests a cancellation. It's still up to you to add code to your DoWork event handler to test whether a cancellation has been requested and stop doing the work if it has. The DoWork event handler can do anything at all so calling CancelAsync is not going to simply abort that on the spot without any consideration for what state the app is in and whether any cleanup may be required.

You know what work is being done so it's up to you write the code such that that work can be cancelled part way through. As it is, all you're doing is a single call to PingAll so there is no way to cancel it. You need to restructure that code, e.g. turn it into a loop that does one ping per iteration and then you can cancel between iterations if required.

Best way to cancel long running process inside backgroundworker

If the problem is isolated your VeryLongRunningProcess from classes like the worker, you can use a Func as a parameter and leave outside your method the worker access

private void VeryLongRunningProcess(Func<bool> isCancelled)
{
var a = Test();

if (isCancelled())
{
return;
}

var b = Test2();

if (isCancelled())
{
return;
}

Thread.Sleep(5000);
var c = Test3();
}

Inside your method, you may check if you must cancel the operation as many times you need. And you can use the Func as a parameter in other methods like Test1, Test2... if any of them takes long time to finish.

Then, you invoke your method in this form:

VeryLongRunningProcess(() => _worker.CancellationPending);

As other people comment, maybe interesting use async/await.

UPDATE

Another way to do if you want choose the use or not of the cancellation:

private void VeryLongRunningProcess(Func<bool> isCancelled = null)
{
var a = Test();

// Or: isCancelled != null && isCancelled()
if (isCancelled?.Invoke() ?? false)
{
return;
}

// ...
}


Related Topics



Leave a reply



Submit