Чистый способ остановить процесс на Win32? - PullRequest
1 голос
/ 17 сентября 2008

При реализации аппликативного сервера и его клиентских библиотек на C ++ у меня возникают проблемы с поиском чистого и надежного способа остановки клиентских процессов при завершении работы сервера в Windows.

Предполагая, что сервер и его клиенты работают под одним и тем же пользователем, требования:

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

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

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

Некоторое время назад я наткнулся на фрагмент кода C (в MSDN, который я считаю), который сделал следующее:

  1. запустить процесс через CreateRemoteThread в процессе до завершения.
  2. заставил этот поток напрямую вызвать ExitProcess.

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

Ответы [ 5 ]

2 голосов
/ 17 сентября 2008

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

Для приложения пользовательского интерфейса оно (поток) может публиковать сообщение в главном окне, WM_ CLOSE или QUIT. Я забыл, который в консольном приложении может выдать CTRL-C или, если код основной консоли зацикливается, он может проверить некоторое условие выхода, установленное потоком.

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

1 голос
/ 24 декабря 2008

Использовать PostMessage или именованное событие.

Re: PostMessage - приложения, отличные от GUI, а также потоки, отличные от потока GUI, могут иметь циклы сообщений, и это очень полезно для подобных вещей. (На самом деле COM использует циклы сообщений под капотом.) Я уже делал это раньше с ATL, но немного подзабыл с этим.

Если вы хотите быть устойчивым к злонамеренным атакам со стороны «плохих» процессов, включите закрытый ключ, общий для клиента / сервера, в качестве одного из параметров в сообщении.

Метод именованных событий, вероятно, проще; используйте CreateEvent с именем, которое является секретным, общим для клиента / сервера, и попросите соответствующее приложение проверить состояние события (например, WaitForSingleObject с таймаутом 0) в своем основном цикле, чтобы определить, следует ли завершить работу.

1 голос
/ 17 сентября 2008

Если вы хотите пойти по маршруту IPC, установите нормальную связь между клиентом и сервером в двух направлениях, чтобы сервер попросил клиентов завершить работу. Или, в случае неудачи, проведите опрос клиентов. Или, в крайнем случае, клиенты должны быть проинструктированы о выходе при отправке запроса на сервер. Вы можете позволить пользователю библиотеки зарегистрировать обратный вызов выхода, но лучший способ, который я знаю, - это просто вызвать «выход» в клиентской библиотеке, когда клиенту приказывают завершить работу. Если клиент застревает в коде завершения работы, сервер должен иметь возможность обходить его, игнорируя структуры данных и соединение этого клиента.

1 голос
/ 17 сентября 2008

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

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

0 голосов
/ 17 сентября 2008

Это очень общий вопрос, и есть некоторые несоответствия.

Хотя это не правило 100%, большинство консольных приложений выполняются до конца, тогда как приложения с графическим интерфейсом работают до тех пор, пока пользователь не завершит их (и службы не будут остановлены через SCM). Следовательно, проще запросить графический интерфейс для закрытия. Вы отправляете им эквивалент Alt-F4. Но для консольной программы вы должны отправить им эквивалент Ctrl-C и надеяться, что они справятся с этим. В обоих случаях вы просто ждете. Если процесс застопорился, вы можете сбить его (TerminateProcess) и молиться, чтобы ущерб был ограничен. Но ваш жесткий диск может заполниться временными файлами.

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

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

...