6

I have different tasks to read from different files and find a word into them. I have put them into a task array which I start with waitAny method as following :

foreach (string file in filesList)
        {
            files[i] = Task.Factory.StartNew(() =>
            {
                mySearch.Invoke(file);
            });
            i++;
        }
        System.Threading.Tasks.Task.WaitAny(files);

I would like to stop all other tasks as soon as one of the tasks finishes (it finishes when it founds the word). For the moment, with waitany, i can know when one tasks finishes, but I don't know how I could know which one has finished and how to stop other tasks. What would be the best way to achieve this ?

Rayjax
  • 7,494
  • 11
  • 56
  • 82
  • Does the completed task leave a result somewhere? That could include the identification of the task. The first task to complete could also set an event, checked by each task in its main loop, that would cause all of the other tasks to exit. – HABO Nov 29 '12 at 16:10
  • in the mySearch.Invoke, their should be a loop iterate through word by word. You can then add a flag so that the loop breaks when the flag is signaled, when any task find the word, you can signal the flag – ComfortablyNumb Nov 29 '12 at 16:10

3 Answers3

3

You can use single CancellationToken which all tasks will share. Inside mySearch.Invoke method verify value of token.IsCancellationRequested to cancel task. When some task will be finished cancel others via CancellationTokenSource.Cancel().

var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token; 

foreach (string file in filesList)
{
   // pass cancellation token to your task
   files[i] = Task.Factory.StartNew(() => mySearch.Invoke(file, token), token);
   i++;
}

Task.WaitAny(files);
tokenSource.Cancel();

BTW you can force token to throw OperationCanceledException when source is canceled by calling token.ThrowIfCancellationRequested()

Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
2

When creating a Task you can pass a CancelationToken. Set this token when one of the tasks finishes. This will cause remaining tasks with this token to not execute. Running tasks can receive a OperationCanceledException and stop too.

Community
  • 1
  • 1
Blachshma
  • 17,097
  • 4
  • 58
  • 72
1

I highly suggest reading How do I cancel non-cancelable async operations? by Stephen Toub. Essentially what you need to do is cancel all of these tasks, but currently you have no mechanism to cancel them.

The ideal approach would be to create a CancellationTokenSource before the foreach, pass the CancellationToken from that source to each of the child tasks, check that token periodically and stop doing work when you notice it's indicated cancellation. You can then cancel the token source in the WhenAny continuation.

If that's not an option you need to decide if it's important to actually stop the tasks (which, really, just can't be done) or if you just need to continue on with your code without waiting for them to finish (that's easy enough to do).

Servy
  • 202,030
  • 26
  • 332
  • 449