Подтвердить что ты не робот

Process.HasExited возвращает true, хотя процесс выполняется?

Я наблюдаю, что Process.HasExited иногда возвращает true, хотя процесс все еще запущен.

Мой код ниже запускает процесс с именем "testprogram.exe", а затем ждет его выхода. Проблема в том, что иногда я получаю исключение; кажется, что даже если HasExited возвращает true, сам процесс все еще жив в системе - как это может быть?

Моя программа записывает файл журнала непосредственно перед его завершением, и поэтому я должен быть абсолютно уверен, что этот файл журнала существует (иначе процесс завершен/закончен) перед его чтением. Постоянная проверка его существования не является вариантом.

// Create new process object
process = new Process();

// Setup event handlers
process.EnableRaisingEvents = true;
process.OutputDataReceived += OutputDataReceivedEvent;
process.ErrorDataReceived += ErrorDataReceivedEvent;
process.Exited += ProgramExitedEvent;

// Setup start info
ProcessStartInfo psi = new ProcessStartInfo
                           {
                               FileName = ExePath,
                               // Must be false to redirect IO
                               UseShellExecute = false,
                               RedirectStandardOutput = true,
                               RedirectStandardError = true,
                               Arguments = arguments
                           };

process.StartInfo = psi;

// Start the program
process.Start();

while (!process.HasExited)
    Thread.Sleep( 500 );

Process[] p = Process.GetProcessesByName( "testprogram" );

if ( p.Length != 0 )
    throw new Exception("Oh oh");

UPDATE: я просто пробовал ждать с process.WaitForExit() вместо цикла опроса, а результат - то же самое.

Дополнение: вышеприведенный код должен был только продемонстрировать "более ясную" проблему. Сделать это ясно; моя проблема НЕ в том, что я все еще могу удержать процесс Process.GetProcessesByName( "testprogram" ); после того, как он установил HasExited в true.

Реальная проблема заключается в том, что программа, которую я запускаю извне, записывает файл - прежде всего - она ​​завершается (изящно). Я использую HasExited для проверки завершения процесса и, следовательно, я знаю, что могу читать файл (потому что процесс вышел!), Но кажется, что HasExited возвращает true даже иногда, когда программа НЕ записала файл на диск еще. Вот пример кода, который иллюстрирует точную проблему:

// Start the program
process.Start();

while (!process.HasExited)
    Thread.Sleep( 500 );
// Could also be process.WaitForExit(), makes no difference to the result

// Now the process has quit, I can read the file it has exported
if ( !File.Exists( xmlFile ) )
{
    // But this exception is thrown occasionally, why?
    throw new Exception("xml file not found");
}
4b9b3361

Ответ 1

Я понимаю, что это старый пост, но в моих поисках, чтобы выяснить, почему мое приложение, работающее с Exited-событием, до того, как приложение даже открылось, я узнал, что, хотя я мог бы быть полезным людям, которые испытывают эту проблему в будущем.

Когда процесс запускается, ему назначается PID. Если после этого Пользователь запрашивает диалоговое окно "Управление учетными записями пользователей" и выбирает "Да", процесс перезапускается и назначается новый PID.

Я сидел с этим в течение нескольких часов, надеюсь, это может сэкономить время.

Ответ 2

Я предлагаю вам попробовать таким образом:

process.Start();

while (!process.HasExited)
{
    // Discard cached information about the process.
    process.Refresh();

    // Just a little check!
    Console.WriteLine("Physical Memory Usage: " + process.WorkingSet64.ToString());

    Thread.Sleep(500);
}

foreach (Process current in Process.GetProcessesByName("testprogram"))
{
    if ((current.Id == process.Id) && !current.HasExited)
        throw new Exception("Oh oh!");
}

В любом случае... на странице MSDN HasExited Я читаю следующее примечание:

Когда стандартный вывод был перенаправлен на асинхронное событие обработчиков, возможно, что обработка вывода не будет иметь завершено, когда это свойство возвращает true. Чтобы убедиться, что асинхронный обработка событий завершена, вызовите перегрузку WaitForExit() который не принимает параметр перед проверкой HasExited.

Это может быть как-то связано с вашей проблемой, поскольку вы перенаправляете все.

Ответ 3

Во-первых, вы уверены, что testprogram не порождает собственный процесс и не выходит, не дожидаясь завершения этого процесса? Мы имеем дело с каким-то состоянием гонки здесь, и тестовая программа может быть значительной.

Второй момент, который я хотел бы сделать, это об этом: "Мне нужно быть абсолютно уверенным, что этот файл журнала существует". Ну, такого не бывает. Вы можете сделать свой чек, а затем файл исчез. Общим способом решения этой проблемы является не проверка, а скорее выполнение того, что вы хотите сделать с файлом. Идите дальше, прочитайте это, поймайте исключения, повторите попытку, если вещь кажется нестабильной, и вы не хотите ничего менять. Функциональный check-and-do не работает хорошо, если в системе есть несколько актеров (нить или что-то еще).

Далее следует последовательность случайных идей.

Вы пытались использовать FileSystemWatcher и не зависели от завершения процесса?

Получается ли это лучше, если вы попытаетесь прочитать файл (не проверяя, существует ли он, но действуют вместо этого) в процессе. Exited event? [это не должно быть]

Является ли система здоровой? Что-нибудь подозрительное в журнале событий?

Может ли быть задействована какая-то действительно агрессивная антивирусная политика?

(Не могу много сказать, не видя весь код и не просматривая тестовую программу.)

Ответ 4

Я знаю, это старый пост, но я могу помочь кому-то.
Класс Process иногда бывает! HasExited вернет true, если процесс вышел из или, если процесс запускается с правами администратора, и ваша программа имеет только пользовательские привилегии.

Ответ 5

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

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

Первое, что пришло мне в голову, это то, что класс Process не лежит, и процесс действительно исчезает, когда он так говорит. Поэтому проблема заключается в том, что на данный момент кажется, что файл по-прежнему недоступен. Я думаю, что это проблема ОС, потому что она содержит некоторые части файла, все еще находящиеся в кеше, который не полностью записан на диск, и инструмент просто вышел из себя, не смывая свои файлы.

С учетом этого вы должны увидеть в журнале, что внешний инструмент создал файл, вышел и ПОСЛЕ того, что файл будет сброшен/закрыт (OS (возможно, удалите все фильтры, когда вы нашли эту точку в журнале)).

Итак, если мои предположения верны, основной причиной было бы плохое поведение вашего внешнего инструмента, который вы не можете изменить, что приведет к простому оживанию немного после выхода процесса и надеемся, что тайм-аут достаточно длинный, чтобы получить файл сбрасывается/закрывается ОС (возможно, попробуйте открыть файл в цикле с таймаутом, пока он не сработает).

Ответ 6

Для начала, есть ли проблема с использованием Process.WaitForExit, а не опроса?

Во всяком случае, технически возможно, чтобы процесс вышел из удобной точки зрения, но процесс по-прежнему остается кратковременным, в то время как он делает что-то вроде кеша флеш-диска. Является ли файл журнала особенно большим (или любая операция, выполняемая на жестких дисках)?

Ответ 7

Есть две возможности: объект процесса продолжает ссылаться на процесс, поэтому он вышел, но он еще не удален. Или у вас есть второй экземпляр процесса. Вы также должны сравнить идентификатор процесса, чтобы убедиться. Попробуйте это.

    ....

    // Start the program
    process.Start();


    while (!process.HasExited)
        Thread.Sleep( 500 );

    Process[] p = Process.GetProcessesByName( "testprogram" );
    if ( p.Length != 0 && p[0].Id == process.id && ! p[0].HasExited)
        throw new Exception("Oh oh");

Ответ 8

По Документация MSDN для HasExited.

Если дескриптор открыт для процесса, операционная система выпускает обрабатывать память, когда процесс вышла, но сохраняет административные информация о процессе, такая как ручку, код выхода и время выхода.

Возможно, это не связано, но стоит отметить.

Если это только проблема 1/10 времени, и процесс в любом случае исчезает через секунду, в зависимости от использования HasExited, попробуйте просто добавить еще одну задержку после проверки HasExited, например

while (!process.HasExited)
    DoStuff();
Thread.Sleep(500);
Cleanup();

и посмотрите, сохраняется ли проблема.

Лично я всегда использовал обработчик событий Exited вместо любого опроса и упрощенную пользовательскую оболочку вокруг System.Diagnostics.Process для обработки таких вещей, как безопасность потоков, завершение вызова CloseMainWindow(), за которым следует WaitForExit(timeout) и, наконец, Kill(), протоколирование и т.д., и никогда не сталкивались с проблемой.

Ответ 9

Может быть, проблема в тестовой программе? Является ли этот код хорошо скрытым/закрытым и т.д.? Мне кажется, если testprogram записывает файл на диск, файл должен быть хотя бы доступен (пустой или нет)

Ответ 10

Если у вас есть веб-приложение, и ваша внешняя программа/процесс генерирует файлы (запись на диск), проверьте, имеет ли ваш IIS права на запись в эту папку, если не на правах безопасности, добавьте разрешение для вашего пользователя IIS, это и было причиной в моем случае я получал process.HasExited = true, но созданные файлы из процесса не были завершены, после некоторого времени я пытаюсь добавить полные разрешения в папку, в которой процесс корчился и обрабатывался. Повторить() как описано Zarathos сверху и все работает как ожидалось.

Ответ 11

Используйте process_name.Refresh(), прежде чем проверять, прошел ли процесс или нет. Refresh() очистит всю кэшированную информацию, связанную с процессом.