2015-12-12 2 views
3

Linux поддерживает механизм ожидания POSIX, определенный в «sys/wait.h». Способы wait, waitid, waitpid могут использоваться для обмена информацией о статусе между родительскими и дочерними процессами, которые были созданы с использованием fork.Какова ближайшая Windows, эквивалентная механизму ожидания POSIX?

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

При переносе Linux приложений, написанных на C или C++ с помощью вилки/ждать Windows, что бы самый правильный родной * способ мониторинга изменения состояния (а именно WEXITED, WSTOPPED, WCONTINUED) дочерних процессов в родительском процессе?

* родной означает использование дополнительных библиотек, фреймворков, программ (таких как cygwin, minGW), которые не поставляются с окнами или предоставляются непосредственно MS в виде среды выполнения.

Edit: В соответствии с просьбой в комментариях я предоставить более подробную информацию о том, что проблема должна быть решена в виде псевдокода:

//creates a new child process that is a copy of the parent (compare 
//POSIX fork()) and returns some sort of handle to it. 
function spawnChild() 

// returns TRUE if called from the master process FALSE otherwise 
function master() 

// return TRUE if called from a child process FALSE otherwise 
function child() 

// returns TRUE if child process has finished its work entirely, 
// FALSE otherwise. 
function completelyFinished() 

//sends signal/message "sig" to receive where receiver is a single 
//handle or a set of handles to processes that shall receive sig 
function sendSignal(sig, receiver) 

// terminates the calling process 
function exit() 

// returns a handle to the sender of signal "sig" 
function senderOf(sig) 

function masterprocess() 
    master //contains handle to the master process 
    children = {} //this is an empty set of handles to child processes 
    buf[SIZE] //some memory area of SIZE bytes available to master process and all children 
    FOR i = 0 TO n - 1 
    //spawn new child process and at its handle to the list of running 
    //child processes. 
    children <- children UNION spawnChild() 
    IF(master()) 
    <logic here> 
    sendSignal(STARTWORKING, children) //send notification to children 
    WHILE(signal = wait()) // wait for any child to respond (wait is blocking) 
     IF signal == IMDONE 
     <logic here (involving reads/writes to buf)> 
     sendSignal(STARTWORKING, senderOf(signal)) 
     ELSEIF signal == EXITED 
     children <- children \ signal.sender //remove sender from list of children 
    ELSEIF(child()) 
    WHILE(wait() != STARTWORKING); 
     <logic here (involving reads/writes to buf)> 
     IF completelyFinished() 
     sendSignal(EXITED, master) 
     exit() 
     ELSE 
     sendSignal(IMDONE, master) 
+6

Процессы Windows не имеют тех же «состояний», что и процессы POSIX. Если вы хотите дождаться завершения процесса, вы можете либо опросить GetExitCodeProcess, либо просто использовать WaitForSingleObject (или один из его родственников) с дескриптором процесса. –

+0

@RogerLipscombe Признавая, что окна, вероятно, не поддерживают эти точные сигналы, я все еще предполагаю, что ther должно быть sth. Связанный. Представьте, что вы разделяете память между процессами (т. Е. С помощью CreateFileMapping). Поэтому, вместо того, чтобы опрос грубой силы для изменений в этой памяти из каждого отдельного процесса (надеюсь) должен быть каким-то образом для любого из связанных процессов, чтобы рассказать другим: «Эй, ребята, я сделал это, пожалуйста, проверьте, важно для вас »или, альтернативно,« Эй, я поставил некоторый запрос в память, пожалуйста, кто-то ответственный процесс и сообщит мне, когда закончите ». – norritt

+4

Итак, вы действительно заинтересованы в обмене между процессами и вообще не заботитесь о сигналах Posix? – usr

ответ

3

Прежде чем ответить на фактический вопрос, я собираюсь рекомендовать лучшее решение: вам следует рассмотреть возможность упрощения отношений между родителем и детьми.

Основываясь на псевдокоде, сигналы между родителем и детьми служат в виде грубой формы cross-process mutex, т.е., все, что они делают, это предотвратить код здесь:

IF signal == IMDONE 
    <logic here (involving reads/writes to buf)> 
    sendSignal(STARTWORKING, senderOf(signal)) 

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

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

(я предположил бы, что современная POSIX также поддерживает какой-то кросс-процесса мьютекс несколько более сложной, чем сигналы.)


Было бы также стоит пересмотреть, действительно ли вам действительно нужно несколько процессов. Несколько потоков будут более эффективными, и если код будет правильно написан, нетрудно будет его адаптировать.


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

  • Отправка сигнала становится записью одного байта.

  • У ребенка, ожидающего сигнала от родителя, становится чтение одного байта.

  • Ожидание родителя сообщениям от любого из детей немного сложнее. Это по-прежнему однобайтовое чтение (для каждого ребенка), но вам нужно будет использовать overlapped I/O и, если вам нужно поддерживать более 64 детей, IOCP.

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

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

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

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


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

+0

Очень красивый, подробный ответ, он наиболее полезен до сих пор, так как вы остаетесь на тему относительно требования, чтобы процессы связывались друг с другом, а не потоками. Также полезны ваши разработки относительно различий между Windows и POSIX. Для заинтересованного читателя я хочу указать, что [именованные каналы] (http://bit.ly/1O36PN8) также доступны в системах POSIX. Я считаю, что есть альтернативный способ сделать это, объединив «CreateFileMapping», «CreateProcess», «CreateEvent», «WaitForMultipleObjects»/'WaitForSingleObject» и «GetExitCodeProcess». – norritt

+0

Что касается вашего предположения о том, что «POSIX также поддерживает какой-то мутекс кросс-процесса, несколько более сложный, чем сигналы». Да, это так, как в Windows, это можно сделать через [Семафоры] (http://www.csc.villanova.edu/~mdamian/threads/posixsem.html). – norritt

2

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

Видя ваше редактирование: события для этого отличные. Создайте именованные события в родительском элементе и передайте их имена в команде подобно детям. Таким образом, родители и ребенок могут сигнализировать друг другу.

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

+0

Вы получаете столько событий, сколько позволяет менеджер объектов. Вы не можете создавать объекты событий, когда система исчерпала ресурсы, или вызывающий абонент достиг своего предела квоты. Это не обязательно * «столько [...], сколько вам нравится» *. – IInspectable

+0

@ Изначально, это правда ... Видите ли вы, что он хочет создать миллионы событий? Я думал больше, как 3. – usr

+0

Не обязательно также искажать ситуацию. Заявив, что вы можете создать столько объектов событий, сколько хотите, ни добавить ничего полезного для ответа, и это не так. Как и все ресурсы, ресурсы объекта ядра ограничены. – IInspectable

2

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

В Win32 вы, вероятно, не реализовали бы это как отдельные процессы.

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

Фактически, вы, вероятно, используете абстракцию более высокого уровня, такую ​​как QueueUserWorkItem. В этом случае используется пул потоков Windows по умолчанию, но вы можете создать свой собственный пул потоков, используя CreateThreadpool.

+0

Это действительно хороший момент. Я слепо предположил, что существует потребность в нескольких процессах. ОП должен уточнить. – usr

+0

В этом случае нитки не являются вариантом. Хотя существует также [стандарт потоков POSIX] (http://man7.org/linux/man-pages/man7/pthreads.7.html), я целенаправленно спрашиваю о подходе, явно использующем отдельные процессы * не * потоки , Как указано в моем исходном вопросе, Windows также поддерживает fork-like нерестование процессов seprate с помощью [CreateProcess] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425%28v=vs.85%29 .aspx). – norritt

+0

@norritt: Нет ничего * «fork-like» * о [CreateProcess] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425.aspx). Он может необязательно наследовать дескрипторы своего «дочернего» процесса (и определенного состояния), но кроме этого, нет никакой связи между дочерним и родительским. Хотя Windows записывает PID родительского процесса, он не используется ни для чего. После запуска дочерние и родительские операции полностью независимы друг от друга. – IInspectable

Смежные вопросы