Как узнать, истек ли срок действия Process.WaitForExit() из-за закрытия основного приложения

У меня есть консольная программа C# "A", чтобы контролировать 4 экземпляра другого приложения "B".

Консольная программа создает один поток на экземпляр "B", и каждый поток запускает "B", используя Process.Start(), Затем поток ждет 3 секунды, используя Process.WaitForExit(3000);

По истечении этого времени он проверяет, работает ли экземпляр приложения "B". Если все в порядке, то снова ждет. В противном случае, если он не работает или если он закончил, он перезапускает его. Когда пользователь закрывает консольную программу, все приложения должны завершиться.

Однако когда приложение "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-го приложения:

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;
}

1 ответ

Я подозреваю, что единственным вариантом является проверка программы выхода из основной программы, чтобы увидеть, запущен ли какой-либо из дочерних процессов, и, если это так, завершить их. Я немного удивлен, что ваш сон 500 мс сопровождается _closing проверка не улавливает это. Хотя, глядя на ваш пример кода, я не вижу _closing установлен флаг (если _closing является вспомогательным полем для MonitoredApp.closing).

Вы могли бы рассмотреть возможность изменения этого _closing логическое к ManualResetEvent что основная программа устанавливает. Вполне возможно, что компилятор оптимизирует проверку _closing, Вы также можете отметить _closing как volatile, что может изменить поведение. Помните, что все это происходит асинхронно, поэтому вам нужно беспокоиться о состоянии гонки.

Несмотря на это, вы, скорее всего, все равно столкнетесь с проблемами, и вам нужно будет убедиться, что основное приложение закрывает все существующие дочерние процессы, прежде чем завершится. Вы просто не можете гарантировать, в каком порядке операционная система завершит работу.

Вы можете избежать этой проблемы, отключив кнопку закрытия. См. Мою запись в блоге, http://blog.mischel.com/2008/07/14/going-too-far-back/, например. Если вы удалите пункт меню Close, нажатие на X не закроет окно.

Конечно, тогда ваши пользователи должны будут ввести команду выхода в вашем окне. И у вас все еще могут быть проблемы, если пользователь закрывает окно из диспетчера задач или другого подобного приложения.

Другие вопросы по тегам