简体   繁体   中英

How to make sure a task is completed in c#

I need to execute a task like this (I do not have control of that task's source code)

public Task DoSomething()

Sometimes that task is failed to complete. And this method will not raise any exception. In this case, I want to execute that task again until it is completed. In order to do so, I try like this :

Task task;
do {
    task = Task.Run(async () => await DoSomething();
    await Task.Delay(300);
}
while (!task.IsCompleted);

Is it correct ? Is there any better way ?

You should invoke async method directly with await .

In case of error an exception should be throw.

Your code should become something like this.

bool repeat = false;
do {
    try 
    { 
        await DoSomething(); 
        repeat = false;
    }
    catch
    {
        repeat = true;
    }
    if (repeat)
        await Task.Delay(300); 
}
while (repeat); // better with some kind of timeout or attempts counter...

Moreover, IsCompleted include also Faulted and Cancelled . If you want to use your approach you need to use new property IsCompletedSuccessfully or exclude IsFault and IsCancelled (if you use an old .NET fwk).

You, probably, want something like this:

  // Trying to complete task again and again... 
  // you may want to give some number of attempt to complete, say 
  // for (int attempt = 1; attempt <= 3; ++i) {
  while (true) {
    // Let task 300 ms to completet before it'll be canceled
    using (CancellationTokenSource cts = new CancellationTokenSource(300)) {
      try {
        await DoSomething(cts.Token);

        // Task Succeeded, break the loop
        break;
      }
      catch (TaskCanceledException) {
        // Task Cancelled, keep on looping
        ;
      }
    }
  }

Note, that you should have some support in DoSomething :

   async Task DoSomething(CancellationToken token)

instead of

   async Task DoSomething()

since we should know how to cancel it. If you don't have

   async Task DoSomething(CancellationToken token)

or alike signature, (with CancellationToken ), the bitter truth is that you can't cancel . You can try wait (and forget the task if it's not completed):

   // Since we are going to forget running tasks, let's
   // restrict number of attempts 
   for (int attempt = 1; attempt <= 3; ++attempt) {
     Task task = DoSomething();

     if (await Task.WhenAny(task, Task.Delay(300)) == task) {
       // task has been completed before timeout
       break;
     } 

     // we forget task (alas, we can't cancel it) and try again
   }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM