0

別のアプリケーション「B」の 4 つのインスタンスを監視する C# コンソール プログラム「A」があります。

コンソール プログラムは、「B」のインスタンスごとに 1 つのスレッドを作成し、各スレッドは を使用して「B」を起動しProcess.Start()ます。次に、スレッドは次を使用して3秒間待機しますProcess.WaitForExit(3000);

その後、アプリケーション「B」のインスタンスが動作しているかどうかを確認します。OKなら、また待ちます。それ以外の場合、機能しない場合、または終了した場合は、再起動します。ユーザーがコンソール プログラムを閉じると、すべてのアプリケーションが終了することが期待されます。

ただし、コンソールの閉じるボタンを使用してアプリケーション「A」を閉じると、すべてのスレッドで WaitForExit() が再開され、アプリケーション「B」が再起動されます。

WaitForExit()監視対象アプリ「B」の障害による再開なのか、メインアプリ「A」の終了による再開なのかを検出したい。この場合、アプリケーション「B」は再起動されず、問題は解決されます。

私は次を使用して終了イベントをキャプチャしようとしました:

[DllImport("Kernel32")]
public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);

問題は、ハンドラ ルーチンが呼び出される前に WaitForExit() が再開されたことです。

詳しくは:

Main() メソッドはスレッドを起動します。

for(int i = 0; i < 4; i++)
{
       Thread t = new Thread(() => MonitorizeApp(arguments));
       t.IsBackground = true;
       t.Start();
}

メインアプリが終了しないように、スレッドをバックグラウンドからフォアグラウンドに変更しようとしましたが、結果は同じです。

各スレッドは、2 番目のアプリケーションの 1 つのインスタンスを起動して監視します。

MonitorizeApp(string arguments)
{
    LaunchProcess(arguments);
    while(!_closing)
    {
        appProcess.WaitForExit(3000);

        if (!_closing)
        {
            if ((appProcess != null) && (!appProcess.HasExited))
                DoSomeMonitoring();
            else
            {
                Console.WriteLine("WARNING: The application finished");
                Thread.Sleep(500);
                if (!_closing)
                {
                    Console.WriteLine("Re-launch");
                    LaunchProcess(arguments);
                    inicial = true;
                }
            }
        }
    }

    Console.WriteLine("\nClosing...\n");
    if(appProcess != null)
    {
        if(!appProcess.HasExited)
            appProcess.Kill();

        appProcess.Dispose();
    }
}

_closing は、コンソールが閉じられたときにメイン スレッドから設定される変数です。SetConsoleCtrlHandler を使用してこれを行いました。

[DllImport("Kernel32")]
public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);

public delegate bool HandlerRoutine(CtrlTypes CtrlType);

private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
{
    MonitoredApp.closing = true;
    Thread.Sleep(1000);
    closing = true;
    Environment.Exit(-1);
    return true;
}
4

1 に答える 1

1

あなたの唯一の選択肢は、メイン プログラムの終了ルーチンで子プロセスが実行されているかどうかを確認し、実行されている場合はそれらを終了させることだと思います。あなたの 500 ミリ秒のスリープとそれに続く_closingチェックがこれをキャッチしないことに少し驚いています。ただし、コード例を見ると、_closingフラグが設定されていません (_closingのバッキング フィールドでない限りMonitoredApp.closing)。

_closingそのブール値をManualResetEventメイン プログラムが設定するに変更することを検討してください。コンパイラが のチェックを最適化していない可能性は十分にあり_closingます。_closingとしてマークすることもできvolatileます。これにより、動作が変わる可能性があります。このようなことはすべて非同期で行われるため、競合状態について心配する必要があることに注意してください。

それでも問題が発生する可能性が高く、メイン アプリケーションが終了する前に、既存のすべての子プロセスを確実に閉じる必要があります。オペレーティング システムがシャットダウンする順序を保証することはできません。

閉じるボタンを無効にすることで問題を回避できます。例として、私のブログ エントリhttp://blog.mischel.com/2008/07/14/going-too-far-back/を参照してください。[閉じる] メニュー項目を削除すると、[X] をクリックしてもウィンドウが閉じなくなります。

もちろん、ユーザーはウィンドウに終了コマンドを入力する必要があります。また、ユーザーがタスク マネージャーやその他の同様のアプリケーションからウィンドウを閉じた場合にも、問題が発生する可能性があります。

于 2015-02-16T22:29:25.547 に答える