I have a main thread that invokes multiple backgroundworkers (in .net/c#).
Each of these threads starts a process in order to run an executable.
When a process ends, I want to tell the main thread to kill all other threads and their respective processes. After all of them stopped, I want to know this and continue to run the main thread for post-processing.
I keep a list of these external processes so I have no problem killing them all. My problem is how to kill all these backgroundworkers. I tried to keep a list of the threads associated with them and kill them from within the first thread that terminates, but apparently this does not kill the backgroundworker itself because the runworkercompleted method is still invoked multiple times.
Does anyone have a pattern on how to kill those workers in a nice way ? should I somehow notify the main thread to do the killing of the other workers ?

- 161
- 1
- 13
-
It will be helpful if you will post the some code of how you create and start threads/process – George Alexandria Aug 22 '17 at 21:29
2 Answers
I'd recommend using async/await and CancellationTokenSources. I'll give advice on how to use BackgroundWorkers as well, but since async/await is so much more convenient (and shorter), it goes first.
async/await is convenient because it gives you the features you're looking for without much added complexity.
private async void SomeEvent(object sender, EventArgs e)
{
CancellationTokenSource cts = new CancellationTokenSource();
var waiter1 = DoSomething(cts.Token);
var waiter2 = DoSomethingElse(cts.Token);
// etc.
// Wait for the first one to finish, then cancel
await Task.WhenAny(waiter1, waiter2, ...).ConfigureAwait(false);
cts.Cancel();
// wait for the remainder to finish
await Task.WhenAll(waiter1, waiter2, ...).ConfigureAwait(false);
// Do Postprocessing
}
Your "waiters" look something like this:
private async Task DoSomething(CancellationToken token)
{
// Do stuff
// Periodically check if someone has finished
if (Token.IsCancellationRequested)
{
// clean up
return;
}
}
async/await code has a few gotchas, including deadlock. Since this sounds like a quick project (I could be wrong), it seems like a good place to learn - especially if there's no massive codebase to rework. If you want to learn more, I think Stephen Cleary's blog is a good place to start, particularly his intro.
On the other hand, if you're absolutely sure you want to use BackgroundWorkers... well I don't blame you, but I don't envy you either.
First, your workers have to know whether somebody else finished first. Use the finished BackgroundWorker's RunWorkerCompleted method to cancel the others BackgroundWorkers:
private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
// Check for errors...
}
else if (e.Cancelled)
{
// Mark that this one has finished
}
else
{
// Assuming you have a set of BackgroundWorkers called "workers"
foreach (var bgw in workers)
bgw.CancelAsync();
// other stuff...
}
}
Then, add a bit of code at the end of your DoWork method to report the cancellation...
private void DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
// Do stuff...
// When "RunWorkerCompleted" is called, let it know whether this worker has been cancelled.
e.Cancel = worker.CancellationPending;
}
And that's it. You can also check the worker.CancellationPending periodically to see if you can finish earlier, but don't forget to assign worker.CancellationPending to e.Cancel before your return!
One last thing: if you want the postprocessing to continue when all workers have finished (and only then), you need to have a way to mark when a particular worker is finished (to cancel the others), and then a way to find out when they've all finished (so you can begin postprocessing). It's doable, and not too difficult - off the top of my head, I'd use a Dictionary<BackgroundWorker, bool>
to indicate which workers have finished. Still, that's another piece of clutter you can avoid with async/await.

- 149
- 2
- 8
From this answer it seems there is no way to kill a Backgroundworker. However this answer shows a workaround by overriding OnDoWork
and keeping a reference to Thread.CurrentThread
. I would still try to have those Backgroundworkers check for a notification to cancel, though.

- 26,556
- 38
- 136
- 291