125

別のスレッドでいくつかのサービスを起動するコンソールアプリケーションについて考えてみます。ユーザーが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
}
4

8 に答える 8

77

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

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

于 2010-04-06T16:48:55.793 に答える
34

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

Console.ReadLine();
于 2010-04-06T16:49:17.850 に答える
13

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

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

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

于 2010-04-06T16:51:25.460 に答える
7

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

static void Main(string[] args) {

   //Do your stuff here

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

   //Cleanup/Before Quit
}

ドキュメントから:

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

于 2014-11-10T11:46:12.703 に答える
7

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

token.WaitHandle.WaitOne();

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

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

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

于 2019-01-22T05:21:41.850 に答える
4

必要以上に難しくしているようです。停止するように通知した後のスレッドだけ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);
        }
    }
}
于 2010-04-07T17:43:58.710 に答える
1

最初の2つのうち1つが優れています

_quitEvent.WaitOne();

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

于 2010-04-06T16:50:06.503 に答える
0

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

于 2010-04-06T17:22:47.770 に答える