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
How to Invoke a UI Method from Another Thread
How to Select Min and Max Values of a Column in a Datatable
How to Draw Directly on the Windows Desktop, C#
Make Listview.Scrollintoview Scroll the Item into the Center of the Listview (C#)
What Are the Downsides to Turning Off Proxycreationenabled for Ctp5 of Ef Code First
Linq to Entities Only Supports Casting Edm Primitive or Enumeration Types with Ientity Interface
Icecast 2: Protocol Description, Streaming to It Using C#
Why We Need Thread.Memorybarrier()
Built in .Net Algorithm to Round Value to the Nearest 10 Interval
Background Color of a Listbox Item (Windows Forms)
How to Copy Part of an Array to Another Array in C#
How to Use Microsoft.Office.Interop.Excel on a MAChine Without Installed Ms Office