System.Diagnostics.Process.Start странное поведение

Я пишу приложение для запуска и мониторинга других приложений на C#. Я использую класс System.Diagnostics.Process для запуска приложений, а затем отслеживаю приложения с помощью свойства Process.Responding для опроса состояния приложения каждые 100 миллисекунд. Я использую Process.CloseMainWindow, чтобы остановить приложение, или Process.Kill, чтобы убить его, если оно не отвечает.

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

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

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

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

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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
8
0
3 983
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

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

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

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

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

Mendelt 24.09.2008 12:13

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

Jarod Elliott 24.09.2008 12:16

Это именно то, что я делаю. Проблема в том, что если я опрашиваю Responding слишком рано после Process.Start, он перестает работать. После этого ответ всегда возвращает истину, и Process.CloseMainWindow тоже перестает работать.

Mendelt 24.09.2008 12:26
Ответ принят как подходящий

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

Разве Process.WaitForInputIdle тебе не поможет? Или я упустил суть? :)

Обновлять

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

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

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

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

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

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

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

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

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

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

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

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

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

Я исследовал это дальше, используя отражатель. Hwnd и некоторые другие свойства сохраняются после того, как вы их получите в первый раз. С Hwnd это может вызвать проблемы. Я описал это здесь blog.mendeltsiebenga.com/post/….

Mendelt 19.10.2008 19:51

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