【问题标题】:Check if task is already running before starting new在开始新任务之前检查任务是否已经在运行
【发布时间】:2013-10-05 11:39:00
【问题描述】:

有一个进程在一个任务中执行。我不希望同时执行其中一个以上。

这是检查任务是否已在运行的正确方法吗?

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                
        });
    }
}

【问题讨论】:

  • 考虑使用Task.IsCompleted - 但请记住,这里总是存在竞争条件。如果任务在您检查后刚刚完成,您将不会再次运行它 - 可以吗?还是您实际上想在第一个任务完成后立即开始第二个任务?
  • 啊,我没看到Task.IsComplete。是的,比赛条件不是问题。感谢并随时创建答案。
  • @davenewza,你可能想看看A pattern for self-cancelling and restarting task

标签: c# .net parallel-processing task-parallel-library


【解决方案1】:

正如 Jon Skeet 所建议的,Task.IsCompleted 是更好的选择。

根据MSDN

IsCompleted 将在任务处于三个之一时返回 true 最终状态:RanToCompletionFaultedCanceled

但它似乎在 TaskStatus.WaitingForActivation 状态下也返回 true。

【讨论】:

  • 你是什么意思“似乎TaskStatus.WaitingForActivation状态下也返回true”? MSDN 文档没有说明:“当任务处于三种最终状态之一时,IsCompleted 将返回 true:RanToCompletion、Faulted 或 Canceled。”
  • 在死锁时,即使任务状态为 WaitingForActivation,任务也可以“完成”!
  • @PoulBak - 我用谷歌搜索,但没有发现任何提及您所说的可能。参考?
  • 嗯,我试过了,这就是我知道的原因。当任务完成时,等待将上下文切换回 UI 线程,这就是它发生的时候(如果有死锁)。
  • 最小复制测试用例,拜托。
【解决方案2】:
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               
        });
    }
}

【讨论】:

  • 为什么要添加TaskStatus.Running等测试?在这些情况下,根据定义,IsCompleted 不是false 吗?也就是说,从文档来看,测试IsCompleted 似乎就足够了,而其他那些测试是多余的(已经包含在IsCompleted 测试中)。
  • @ToolmakerSteve。对不起,我不记得我为什么这样做了,因为我在 5 年前写过这篇文章。无论如何,这是 C#,因此对于 OR 语句,一旦发现 task.IsCompleted 为假,程序就会跳过其他测试。此外,SOF 是一个面向程序员的教育网站,因此通过此代码,他们可以快速了解任务的不同状态。
  • 我不明白这一点 - 在任务运行之前您无法检查任务的状态,否则您将收到对象尚未初始化的异常。一旦它开始运行,再检查 status = Running 已经太晚了,因为它是。我想我错过了一些非常明显的东西......但我无法理解
  • @Journeyman1234 完成的任务并不意味着它被销毁。这意味着,任务已完成,正在休息。任务的其他状态有等待、中断、运行等。在这些状态下,任务的实例仍然存在。您描述的状态将是任务从未启动(调用/启动)时的状态。在这种状态下,它不会出现在任务列表中。所以搜索它会返回null。这段代码还包含了如果它为空该怎么做的指令。
  • @Sayka 谢谢老兄,我在此期间想通了,现在一切都很好:)
【解决方案3】:

您可以通过以下方式进行检查:

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

【讨论】:

    【解决方案4】:

    更简单:

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

    【讨论】:

    • 更简单:if (task?.IsCompleted)(你不需要== true
    • 除了task?.IsCompleted 产生一个可为空的布尔值。无论哪种情况, task.IsCompleted 都不是一个充分的检查; @Sayka 有更好的答案。
    • @MarkMintoff 是真的! if (task?.IsCompleted ?? false)应该更好
    【解决方案5】:

    按照@Mohammad Kohanrooz 的回答,这是我的扩展方法:

    /// <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;
    }
    

    像这样使用它:

    if(myOwnTask.IsRunning())
    {
        Logger.Log("Task is already running");  
    }
    else
    {
        Logger.Log("Starting new task");    
        myOwnTask = StartNewTask(); 
    }
    

    【讨论】:

      猜你喜欢
      • 2019-12-11
      • 1970-01-01
      • 1970-01-01
      • 2014-12-15
      • 1970-01-01
      • 2012-11-11
      • 1970-01-01
      • 2010-12-07
      相关资源
      最近更新 更多