如何让.NET控制台应用程序运行?

时间:2010-04-06 16:45:58

标签: c# multithreading sleep manualresetevent

考虑一个Console应用程序,它在一个单独的线程中启动某些服务。它需要做的就是等待用户按Ctrl + C将其关闭。

以下哪项是更好的方法?

static ManualResetEvent _quitEvent = new ManualResetEvent(false);

static void Main() {
    Console.CancelKeyPress += (sender, eArgs) => {
        _quitEvent.Set();
        eArgs.Cancel = true;
    };

    // kick off asynchronous stuff 

    _quitEvent.WaitOne();

    // cleanup/shutdown and quit
}

或者,使用Thread.Sleep(1):

static bool _quitFlag = false;

static void Main() {
    Console.CancelKeyPress += delegate {
        _quitFlag = true;
    };

    // kick off asynchronous stuff 

    while (!_quitFlag) {
        Thread.Sleep(1);
    }

    // cleanup/shutdown and quit
}

8 个答案:

答案 0 :(得分:58)

总是希望阻止使用while循环,尤其是在强制代码重新检查变量时。它会浪费CPU资源并降低程序速度。

我肯定会说第一个。

答案 1 :(得分:27)

或者,更简单的解决方案就是:

Console.ReadLine();

答案 2 :(得分:12)

您可以这样做(并删除CancelKeyPress事件处理程序):

while(!_quitFlag)
{
    var keyInfo = Console.ReadKey();
    _quitFlag = keyInfo.Key == ConsoleKey.C
             && keyInfo.Modifiers == ConsoleModifiers.Control;
}

不确定这是否更好,但我不喜欢在循环中调用Thread.Sleep的想法。我认为阻止用户输入更清晰。

答案 3 :(得分:9)

我更喜欢使用 Application.Run

static void Main(string[] args) {

   //Do your stuff here

   System.Windows.Forms.Application.Run();

   //Cleanup/Before Quit
}

来自文档:

  

开始在当前线程上运行标准的应用程序消息循环,没有表单。

答案 4 :(得分:3)

好像你让它变得比你需要的更难。为什么不在你发信号通知停止后只用Join线程?

class Program
{
    static void Main(string[] args)
    {
        Worker worker = new Worker();
        Thread t = new Thread(worker.DoWork);
        t.IsBackground = true;
        t.Start();

        while (true)
        {
            var keyInfo = Console.ReadKey();
            if (keyInfo.Key == ConsoleKey.C && keyInfo.Modifiers == ConsoleModifiers.Control)
            {
                worker.KeepGoing = false;
                break;
            }
        }
        t.Join();
    }
}

class Worker
{
    public bool KeepGoing { get; set; }

    public Worker()
    {
        KeepGoing = true;
    }

    public void DoWork()
    {
        while (KeepGoing)
        {
            Console.WriteLine("Ding");
            Thread.Sleep(200);
        }
    }
}

答案 5 :(得分:2)

其中第一个是更好的

_quitEvent.WaitOne();

因为在第二个线程中,线程每隔一毫秒唤醒就会转入OS中断,这很昂贵

答案 6 :(得分:0)

你应该像编写Windows服务一样。你永远不会使用while语句,而是使用委托。等待线程处理时通常使用WaitOne() - Thread.Sleep() - 不可取 - 您是否考虑过使用System.Timers.Timer来检查关闭事件?

答案 7 :(得分:0)

还可以基于取消令牌来阻止线程/程序。

token.WaitHandle.WaitOne();

当令牌被取消时,会发出WaitHandle信号。

我已经看到Microsoft.Azure.WebJobs.JobHost使用的这项技术,其中的令牌来自WebJobsShutdownWatcher(结束工作的文件监视程序)的取消令牌源。

这可以控制程序何时结束。