使用.NET 4.0任务的.NET控制台应用程序如何正确退出

3

我有一个控制台应用程序,它基本上看起来像这样

class Program
{
    static void Main(string[] args)
    {
        DoStuffService svc = new DoStuffService();
        svc.Start();
    }
}


class DoStuffService
{
    public void Start()
    {
        Task.Factory.StartNew(() => { LongRunningOperation() });
    }

    private void LongRunningOperation()
    {
        // stuff
    }    
}

如今保证控制台应用程序在LongRunningOperation()完成之前不退出的最佳方法是什么?同时,是否有一种方式可以通知控制台应用程序(例如用于日志记录)LongRunningOperation()已经完成。

3个回答

3

在任务上调用Wait()。例如:

class Program
{
    static void Main(string[] args)
    {
        DoStuffService svc = new DoStuffService();
        svc.Start();
        // stuff...
        svc.DelayTilDone();
    }
}


public class DoStuffService
{
    Task _t;
    public void Start()
    {
        _t = Task.Factory.StartNew(() => { LongRunningOperation(); });
    }

    public void DelayTilDone()
    {
        if (_t==null) return;
        _t.Wait();
    }

    private void LongRunningOperation()
    {
        System.Threading.Thread.Sleep(6000);
        System.Console.WriteLine("LRO done");
    }
}

在编程中,而不是添加 DelayTilDone()Start() 返回一些东西(例如任务或等待句柄)让 Program 使用来启动 Wait() 是否合理? - kenwarner
@qntmfred:任务没有公开 WaitHandle,因此您必须返回 Task 对象。更复杂的方法是让 Start 调用 .ContinueWith 和一个方法来信号化您提供的句柄,您可以在其上等待。 - Tergiver
返回Task对象是有道理的,但此时我在想DoStuffService类的目的是什么。如果您公开它使用的Task,为什么不直接从调用者使用TaskFactory呢? - Cheeso
我希望在新线程上运行DoStuffService,无论它是在控制台应用程序、WPF应用程序、asp.net应用程序等中使用。这就是为什么DoStuffService使用TaskFactory的原因。我希望在控制台应用程序中知道该线程何时完成,但我不关心在其他应用程序中何时完成。 - kenwarner

1
除了Cheeso的答案之外,您还需要处理Console.CancelKeyPress,以便您可以显示繁忙消息并设置e.Cancel = True
您无法防止他们终止进程,但至少可以处理Ctrl+C和Ctrl+Break。

0

有一个类似的线程C#多线程控制台应用程序-控制台在线程完成之前退出

您可以简单地返回一个已启动的任务并在其上使用Wait()ContinueWith()

using System.Diagnostics;
using System.Threading.Tasks;

class Program
{

  static void Main(string[] args)
  {
    DoStuffService svc = new DoStuffService();
    svc.Start().Wait();//bool res = svc.Start() 
    Trace.WriteLine("333333333333333");
  }
}
public class DoStuffService
{
  public Task Start()
  {
    return Task.Factory.StartNew
      (() =>
      {
        Trace.WriteLine("111111111");
        LongRunningOperation(); ;
      });
  }
  private void LongRunningOperation()
  {
    System.Threading.Thread.Sleep(3000);
    Trace.WriteLine("2222222222");
  }
}

一个任务将阻塞父线程,直到完成,如果访问它的结果属性,因此:
using System.Diagnostics;
using System.Threading.Tasks;

class Program
{
   static void Main(string[] args)
   {
     DoStuffService svc = new DoStuffService();
     svc.Start();//bool res = svc.Start() 
     Trace.WriteLine("333333333333333");
   }
}
public class DoStuffService
{
   public Task<bool> MyTask;
   public bool Start()
   {
      MyTask = Task.Factory.StartNew<bool>
        (() =>
        {
          Trace.WriteLine("111111111");

          return LongRunningOperation();;
        });
      return MyTask.Result;
    }
    private bool LongRunningOperation()
    {
      System.Threading.Thread.Sleep(3000);
      Trace.WriteLine("2222222222");
      return true;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接