38

There is a process which is executed in a task. I do not want more than one of these to execute simultaneously.

Is this the correct way to check to see if a task is already running?

private Task task;

public void StartTask()
{
    if (task != null && (task.Status == TaskStatus.Running || task.Status == TaskStatus.WaitingToRun || task.Status == TaskStatus.WaitingForActivation))
    {
        Logger.Log("Task has attempted to start while already running");
    }
    else
    {
        Logger.Log("Task has began");

        task = Task.Factory.StartNew(() =>
        {
            // Stuff                
        });
    }
}
Dave New
  • 38,496
  • 59
  • 215
  • 394
  • 12
    Consider using `Task.IsCompleted` - but bear in mind that there'll always be a race condition here. If the task completes *just* after you check, you won't run it another time - is that okay? Or do you *actually* want to start a second task as soon as the first one finishes? – Jon Skeet Oct 05 '13 at 11:40
  • Ah, I didn't see `Task.IsComplete`. Yes, the race condition is not a problem. Thanks and feel free to create an answer. – Dave New Oct 05 '13 at 12:13
  • @davenewza, you may want to check out [A pattern for self-cancelling and restarting task](http://stackoverflow.com/questions/18999827/a-pattern-for-self-cancelling-and-restarting-task) – noseratio Oct 06 '13 at 01:35

5 Answers5

37

As suggested by Jon Skeet, the Task.IsCompleted is the better option.

According to MSDN:

IsCompleted will return true when the task is in one of the three final states: RanToCompletion, Faulted, or Canceled.

But it appears to return true in the TaskStatus.WaitingForActivation state too.

Dave New
  • 38,496
  • 59
  • 215
  • 394
  • What do you mean "*appears* to return true in the `TaskStatus.WaitingForActivation` state too"? The MSDN documentation doesn't state that: "IsCompleted will return true when the task is in one of the three final states: RanToCompletion, Faulted, or Canceled." – Doug S Jun 28 '18 at 13:09
  • On a deadlock the Task can 'complete' even when its status is WaitingForActivation! – Poul Bak Aug 16 '18 at 01:57
  • 1
    @PoulBak - I googled, but did not find any mention that what you say is possible. Reference? – ToolmakerSteve Sep 25 '18 at 22:43
  • Well, I have tried it, that's why I know. When the task has completed, waiting to switch context back to the UI thread, that's when it happen (if there's a deadlock). – Poul Bak Sep 25 '18 at 22:46
  • 4
    Minimal reproduction test-case, please. – user2864740 Nov 22 '19 at 00:08
15
private Task task;

public void StartTask()
{
    if ((task != null) && (task.IsCompleted == false ||
                           task.Status == TaskStatus.Running ||
                           task.Status == TaskStatus.WaitingToRun ||
                           task.Status == TaskStatus.WaitingForActivation))
    {
        Logger.Log("Task is already running");
    }
    else
    {
        task = Task.Factory.StartNew(() =>
        {
            Logger.Log("Task has been started");
            // Do other things here               
        });
    }
}
Abdul Saleem
  • 10,098
  • 5
  • 45
  • 45
  • 2
    Why do you add the tests for TaskStatus.Running, etc? Isn't it the case that, by definition, `IsCompleted` will be `false` in those cases? That is, from the documentation, it would seem that testing `IsCompleted` is sufficient, and those other tests are redundant (are already included in `IsCompleted` test). – ToolmakerSteve Sep 25 '18 at 22:47
  • @ToolmakerSteve. Iam sorry that I dont remember why I did that because I've written this 5 years back. Anyways this is c# so as for OR statements, the program will skip other tests as soon as the task.IsCompleted is found false. Also, SOF is an educational site for programmers, so with this code they can get a quick look at different states of a task. – Abdul Saleem Sep 27 '18 at 20:47
  • I don't understand this - you cannot check the task's status until it is running, or you'll get an exception that the object hasn't been initialised. Once it is running, it's too late to check if status = Running, because it is. I think i'm missing something really obvious... but I can't thing what – Journeyman1234 May 11 '19 at 22:44
  • @Journeyman1234 A completed task doesnt mean that it is destroyed. It means, the task is completed and it is resting. Other states of tasks are waiting, interrupted, running etc.. In these states, an instance of the task will be still there. The state that you describe will be that when the task is never been initiated (called/started). In that state, it will not be in the list of tasks. So a search for it will return null. This piece of code also includes instruction for what to do if it is null. – Abdul Saleem May 12 '19 at 15:04
2

You can check it with:

if ((taskX == null) || (taskX.IsCompleted))
{
   // start Task
   taskX.Start();
   //or
   taskX = task.Factory.StartNew(() =>
   {
      //??
   }
}
guest123
  • 21
  • 1
0

Even easier:

if (task?.IsCompleted ?? true)
    task = TaskFunction();
-1

Following @Mohammad Kohanrooz answer, here is my extension method:

/// <summary>
/// Checks if task is running.
/// </summary>
/// <param name="task">Task to evaluate</param>
/// <returns>True if task is not completed or it's value is null</returns>
public static bool IsRunning(this Task task)
{
    return !task?.IsCompleted ?? false;
}

Use it like:

if(myOwnTask.IsRunning())
{
    Logger.Log("Task is already running");  
}
else
{
    Logger.Log("Starting new task");    
    myOwnTask = StartNewTask(); 
}
Lotan
  • 4,078
  • 1
  • 12
  • 30