2011-12-01 13 views
6

私はそれ自身のスレッドで実行され、ブロックせずに起動/停止することができるプロセスを持っています。これは最終的にWindowsサービスに入りますが、コンソールアプリケーションでこれを設定しています。これは完全に完了するまでです。whileループの代わりにセマフォを使用する。これは良いか悪いですか?

Start()を呼び出した後、Ctrl-Cを押すまでメインプログラムスレッドをブロックします。私は、これが動作することを知っている:

public static void Main(string[] args) 
{ 
    bool keepGoing = true; 

    var service = new Service(); 

    System.Console.TreatControlCAsInput = false; 

    System.Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) 
    { 
     e.Cancel = true; 
     service.Stop(); 
     keepGoing = false; // Break the while loop below 
    }; 

    service.Start(); 

    while(keepGoing) 
    { 
     Thread.Sleep(100); // 100 is arbitrary 
    } 

} 

しかし、私はフラグと、任意の睡眠値が面倒見つけます。私はCPUコストがwhileループでは実質的に0であることを知っていますが、Ctrl-Cハンドラが終了するとすぐに「ハード」ブロックをリリースします。私は匿名のCtrl-Cハンドラが完了するまでセマフォを使って以下を考案しました:

public static void Main(string[] args) 
{ 
    var service = new Service(); 

    var s = new Semaphore(1, 1); 

    System.Console.TreatControlCAsInput = false; 

    System.Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) 
    { 
     e.Cancel = true; 
     service.Stop(); 
     s.Release(); // This will allow the program to conclude below 
    }; 

    service.Start(); 

    s.WaitOne(); // This will not block 
    s.WaitOne(); // This will block w/o CPU usage until the sempahore is released 

} 

これは悪い設計ですか?それは過労ですか?それは危険ですか?

EDIT:

次のように私はまたAppDomain.CurrentDomain.UnhandledExceptionをフックアップ:

AppDomain.CurrentDomain.UnhandledException += delegate { 
    service.Stop(); 
    s.Release(); 
}; 

EDIT 2位:

を私はそれがことが重要であることに注意してくださいStop()メソッドは終了時に呼び出されます。 @Adam Ralphは、ハイブリッドコンソール/サービスの完全なパターンを持っていますが、Qに答えるときにはこの情報を持っていませんでした。

+1

whileループを避けることができれば、追求する価値があると言います。 – ChaosPandion

+1

プロトタイプ作成では、後者の方がはるかに改善されています。プロダクションアプリケーションでは、私は全体の "CTRL + C"ブレークアイデアを避けるでしょう。シグナルを使用してスレッドを強制終了します。シグナルが 'Set()'のやり方は、他の層に依存します。サービスを設計するときは、これを覚えておいてください。 'Set()'を呼び出すことができるメソッドのような手段を追加してください。 –

+0

@ P.Brian。Mackey:これはプロダクションアプリケーションではありませんが、*の場合は、非対話型のコンソールアプリケーションでCtrl-Cをうまく処理することは賢明ではないでしょうか?そのままでは、Ctrl + Cは終了する前にクリーンアップする機会を持たずに単にプログラムをシャットダウンします。最終的に、私は単に、while(flag)Thread.Sleep(...)オプションに対するセマフォー・ソリューションかどうか疑問に思っていました。 –

答えて

4

私たちはいくつかのアプリで同様の要件を持っています。それらはWindowsサービスですが、デバッグのためにコンソールアプリケーションとして実行することがよくあります。さらに、私たちは通常、新しいサービスをかなり早い段階でWindowsサービスとして作成しますが、コンセプトを証明した後は、実際にサービスとして実行する必要がないことがよくあります。

これは私たちのパターンです使用: - 無限にスリープ状態にスレッドを告げる

using (var service = new Service()) 
{ 
    if (Environment.UserInterActive) 
    { 
     service.Start(); 
     Thread.Sleep(Timeout.Infinite); 
    } 
    else 
    { 
     ServiceBase.Run(service); 
    } 
} 

が非効率的に見えるかもしれないが、これはシナリオをデバッグするためだけで、冗長スレッドがほとんどで構成されて何のCPU時間、(約1MB)だけでいくつかのメモリを、費用はかかりませんスレッドに割り当てられたスタック領域。 Ctrl + Cまたはコマンドウィンドウを閉じることで、プロセスを終了することができます。

- EDIT -

にCtrl + Cを押す(すなわち失礼な中断が起こる)とDispose()への呼び出しが不可欠であるされている場合service.Dispose()が呼び出されていないことが判明した場合、その後、私はあなたが明示的に行うことができると思いますこのようなので: - Stop()Dispose()にカプセル化されるべきであると

using (var service = new Service()) 
{ 
    if (Environment.UserInterActive) 
    { 
     Console.CancelKeyPress += (sender, e) => service.Dispose(); 
     service.Start(); 
     Thread.Sleep(Timeout.Infinite); 
    } 
    else 
    { 
     ServiceBase.Run(service); 
    } 
} 

注意。

+0

'UserInterActive'コンテキストで、ユーザが(Ctrl-Cまたはウィンドウクローズを使用して)プロセスを停止しようとした場合、' Stop() 'メソッドは呼び出されないという問題はありません?これは私の上の私の例で達成しようとしているものです。 –

+0

私たちのサービスでは、Stopメソッドを呼び出すことは重要ではありませんが、引き続きCancelKeyPressに登録して明示的に行うことができます。私は答えを編集します –

+0

Qでこれについてはっきりしていませんでした。そのために残念。私はこれに言及して編集した。 –

関連する問題