Система.Диагностика.Процесс.Начало странного поведения

StackOverflow https://stackoverflow.com/questions/125934

  •  02-07-2019
  •  | 
  •  

Вопрос

Я пишу приложение для запуска и мониторинга других приложений на C #.Я использую System.Диагностика.Класс Process для запуска приложений, а затем мониторинга приложений с помощью Process.Свойство Responsing для опроса состояния приложения каждые 100 миллисекунд.Я использую Процесс.Закройте основное окно, чтобы остановить приложение или процесс.Убейте, чтобы убить его, если он не реагирует.

Я заметил странное поведение, при котором иногда объект process переходит в состояние, при котором свойство responsing всегда возвращает true, даже когда базовый процесс зависает в цикле и когда он не реагирует на CloseMainWindow.

Один из способов воспроизвести это - опросить Отвечающее свойство сразу после запуска экземпляра процесса.Так, например

_process.Start();
bool responding = _process.Responding;

будет воспроизводить состояние ошибки, пока

_process.Start();
Thread.Sleep(1000);
bool responding = _process.Responding;

будет работать.Уменьшение периода ожидания до 500 приведет к повторному переходу в состояние ошибки.

Что-то в вызове _process .Слишком быстрый ответ после запуска, похоже, не позволяет объекту получить правильный обработчик очереди сообщений Windows.Я думаю, мне нужно дождаться _process.Начните, чтобы закончить выполнение этой асинхронной работы.Есть ли лучший способ дождаться этого, чем вызов Thread.Sleep?Я не слишком уверен, что 1000 мс всегда будет достаточно.

Это было полезно?

Решение

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

Это не так Обрабатывать.WaitForInputIdle может быть, вам чем-нибудь помочь?Или я упускаю суть?:)

Обновить

После беседы в Твиттере (или твит-чириканья?) с Менделтом я подумал, что должен обновить свой ответ, чтобы сообщество было в курсе..

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

Надеюсь, это поможет :)

Другие советы

Я думаю, что, возможно, было бы лучше усилить проверку _process.Отвечать так, чтобы вы пытались остановить / завершить процесс только в том случае, если свойство Responsing возвращает false более 5 секунд (например).

Я думаю, вы можете обнаружить, что довольно часто приложения могут "не отвечать" в течение доли секунды, пока они выполняют более интенсивную обработку.

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

Дополнительное примечание:В документации Microsoft указано, что свойство Responsing конкретно относится к пользовательскому интерфейсу, именно поэтому при новом запуске процесса пользовательский интерфейс может отвечать не сразу.

Спасибо за ответы.Это

_process.Start();
_process.WaitForInputIdle();

Кажется, это решает проблему.Это все еще странно, потому что Responsing и WaitForInputIdle должны оба использовать один и тот же вызов win32 api под прикрытием.

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

Мне придется погрузиться в reflector, чтобы посмотреть, смогу ли я разобраться в этом.

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

_process.Start();
IntPtr mainWindow = _process.MainWindowHandle;

Я проверил с помощью Reflector, и это то, что Responsing делает под одеялом.Кажется, что если вы получаете MainWindowHandle слишком рано, вы получаете неправильный, и он использует эту неправильную обработку до конца срока службы процесса или до тех пор, пока вы не вызовете Refresh();

Обновить
Вызов WaitForInputIdle() решает проблему только в какой-то момент времени.Вызов Refresh() каждый раз, когда вы читаете свойство Responsing, кажется, работает лучше.

Я тоже заметил это в одном проекте около 2 лет назад.Я вызвал .Refresh() перед запросом определенных значений prop.Это был метод проб и ошибок, чтобы определить, когда мне нужно было вызвать.Обновить().

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top