web-dev-qa-db-ja.com

.NETコンソールアプリを実行し続ける方法

一部のサービスを別のスレッドで起動するコンソールアプリケーションを検討してください。ユーザーが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
}
93
intoOrbit

特にコードに変数の再チェックを強制する場合は、Whileループの使用を常に禁止する必要があります。 CPUリソースを浪費し、プログラムの速度を低下させます。

私は間違いなく最初のものを言うでしょう。

58
Mike

または、より単純な解決策は次のとおりです。

Console.ReadLine();
27
Cocowalla

あなたはそれを行うことができます(そしてCancelKeyPressイベントハンドラを削除します):

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

それが良いかどうかはわかりませんが、ループでThread.Sleepを呼び出すという考えは好きではありません。ユーザー入力をブロックする方がクリーンだと思います。

12
Thomas Levesque

Application.Runを使用することを好みます

static void Main(string[] args) {

   //Do your stuff here

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

   //Cleanup/Before Quit
}

ドキュメントから:

フォームなしで、現在のスレッドで標準アプリケーションメッセージループの実行を開始します。

9
ygaradon

必要以上に難しくしているようです。停止するように信号を送った後、スレッドをただ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);
        }
    }
}
3
Ed Power

最初の2つの方が良い

_quitEvent.WaitOne();

2番目のスレッドでは、スレッドが1ミリ秒ごとにウェイクアップするため、OS割り込みが発生しますが、これは高価です

2
Naveen

キャンセルトークンに基づいてスレッド/プログラムをブロックすることもできます。

token.WaitHandle.WaitOne();

トークンがキャンセルされると、WaitHandleが通知されます。

Microsoft.Azure.WebJobs.JobHostで使用されるこの手法を見てきました。トークンはWebJobsShutdownWatcher(ジョブを終了するFile Watcher)のキャンセルトークンソースから取得されます。

これにより、プログラムをいつ終了できるかをある程度制御できます。

0
CRice

Windowsサービスをプログラミングする場合と同じように行う必要があります。デリゲートを使用する代わりに、whileステートメントを使用することはありません。通常、WaitOne()は、スレッドの破棄を待機しているときに使用されます-Thread.Sleep()-表示されません-そのイベントを使用してSystem.Timers.Timerを使用してシャットダウンイベントを確認することを考えましたか?

0
KenL