Execl   execvp запустить процесс


Содержание

_execvp, _wexecvp _execvp, _wexecvp

Загружает и выполняет новые дочерние процессы. Loads and executes new child processes.

Этот API нельзя использовать в приложениях, выполняемых в среде выполнения Windows. This API cannot be used in applications that execute in the Windows Runtime. Дополнительные сведения: Функции CRT, которые не поддерживаются в приложениях универсальной платформы Windows. For more information, see CRT functions not supported in Universal Windows Platform apps.

Синтаксис Syntax

Параметры Parameters

кмднаме cmdname
Путь к выполняемому файлу. Path of the file to execute.

argv argv
Массив указателей на параметры. Array of pointers to parameters.

Возвращаемое значение Return Value

В случае успешного выполнения эти функции не возвращаются к вызывающему процессу. If successful, these functions do not return to the calling process. Возвращаемое значение, равное-1, указывает на ошибку . в этом случае задается глобальная переменная «пробуждение». A return value of -1 indicates an error, in which case the errno global variable is set.

значение по значению errno value Описание Description
E2BIG E2BIG Пространство, требуемое для аргументов и параметров среды, превышает 32 КБ. The space required for the arguments and environment settings exceeds 32 KB.
EACCES EACCES Указанный файл имеет нарушение блокировки или общего доступа. The specified file has a locking or sharing violation.
EINVAL EINVAL Недопустимый параметр. Invalid parameter.
EMFILE EMFILE Открыто слишком много файлов (указанный файл необходимо открыть и определить, является ли он исполняемым). Too many files open (the specified file must be opened to determine whether it is executable).
ENOENT ENOENT Файл или путь не найдены. The file or path not found.
ENOEXEC ENOEXEC Указанный файл не является исполняемым или имеет недопустимый формат исполняемого файла. The specified file is not executable or has an invalid executable-file format.
ENOMEM ENOMEM Недостаточно доступной памяти для выполнения нового процесса; либо доступная память повреждена, либо существует недопустимый блок, что указывает на неправильное выделение памяти для процесса, а значит вызывающий процесс был выделен ненадлежащим образом. Not enough memory is available to execute the new process; the available memory has been corrupted; or an invalid block exists, indicating that the calling process was not allocated properly.

Дополнительные сведения об этих и других кодах возврата см. в разделе _doserrno, errno, _sys_errlist и _sys_nerr. For more information about these and other return codes, see _doserrno, errno, _sys_errlist, and _sys_nerr.

Примечания Remarks

Каждая из этих функций загружает и выполняет новый процесс, передавая массив указателей на аргументы командной строки и используя переменную среды path для поиска файла для выполнения. Each of these functions loads and executes a new process, passing an array of pointers to command-line arguments and using the PATH environment variable to find the file to execute.

Функции _execvp проверяют свои параметры. The _execvp functions validate their parameters. Если кмднаме является пустым указателем, или argv является пустым указателем, указатель на пустой массив или если массив содержит пустую строку в качестве первого аргумента, эти функции вызывают обработчик недопустимых параметров, как описано в разделе Проверка параметров. . If the cmdname is a null pointer, or argv is a null pointer, pointer to an empty array, or if the array contains an empty string as the first argument, these functions invoke the invalid parameter handler as described in Parameter Validation. Если выполнение может быть продолжено, эти функции устанавливают значение еинвал и возвращают-1. If execution is allowed to continue, these functions set errno to EINVAL and return -1. Ни один процесс не запущен. No process is launched.

Требования Requirements

Дополнительные сведения о совместимости см. в разделе Совместимость. For more compatibility information, see Compatibility.

процесс — C ++: execv / execvp не использует существующий P >

У меня есть программа C ++, которая работает как служба Linux. Некоторые параметры командной строки программы просто устанавливают значения в ее файлах конфигурации и затем завершаются, что требует перезапуска службы для получения новой конфигурации. Чтобы служба могла продолжать работу без перерыва, она работает следующим образом:

  • фоновая служба запускается при загрузке системы
    • Фоновая служба создает конфигурационные файлы мониторинга потоков ‘config watchdog’
  • пользователь запускает «опции progname» из командной строки
    • файлы конфигурации изменены
    • Экземпляр командной строки программы выхода
    • сторожевой поток конфигурации фоновой службы обнаруживает изменения в конфигурации, запускает перезагрузку

Когда программа перезапускается после прочтения новой конфигурации, я вызываю execv, чтобы она оставалась в том же пространстве процесса, что и исходный экземпляр, чтобы продолжать управлять им как службой. Проблема в том, что execv не ведет себя должным образом, а вместо этого завершает существующий процесс и перезапускает новый. Поскольку PID больше не совпадает, если я попытаюсь запустить «сервисный прогон stop / restart» после этой точки, он не будет работать должным образом, «stop» оставит сервис запущенным, а «restart» вызовет дубликат экземпляра программы ,

Я подтвердил, что argv [0], передаваемый execv, является полным путем к исполняемому файлу, поэтому он не должен искать исполняемый файл в PATH через оболочку (что также должно быть предотвращено тем, что я использую execv вместо execvp), который я прочитал о том, чтобы вызывать подобные проблемы в других приложениях.

Решение

Обнаружил проблему, проблема была в том, что программа использует daemon () при запуске, которая выполняет fork / exec внутри, и при перезапуске программы она снова вызывала daemon (). После его улучшения, чтобы различать запуск / перезапуск и избежать повторного вызова daemon (), проблема исправлена.

execvp и его аргументы

Имею задачу, написать простенький интерпретатор shell’a, грубо говоря надо просто разобрать ввод и выполнить команду через execvp.

Сразу её синтаксис из мана:
int execvp(char * name, char *argv[]);
с первым аргументом нету проблем, а вот со вторым.. Требуется тип char* const*, нужно, исходя из задачи, получить его динамически (со стандартного ввода), за лето потерял навык и смог разобрать ввод только через ограниченный массив char[256], затем попытался явно привести его к char* const* и передать в execvp, аллилуя, скомпилилось, но процесс не запускается » />

И как бы намекают, что массив fl заполнен правильно, первый элемент — имя файла, далее аргументы\ключи.

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

Можно сделать примерно так:

И все будет работать, но это, как Вы уже поняли, не подходит.

Вообще проблема изначально не в execvp, я просто не понимаю в чем разница.. В любом случае при передаче массива я передаю указатель на первый элемент, так какая разница char[256] ли это или char* const*..

execl, execle, execlp, execlpe, execv, execve, execvp, execvpe

int execle(char *fname, char *arg0, . char *argN, NULL, char *envp[ ])

int execlpe(char *fname, char *arg0, . char *argN, NULL, char *envp[ ])

int execve(char *fname, char *arg[ ], char *envp[ ])

int execvpe(char *fname, char *arg[ ], char *envp[ ])

Эти функции не определены стандартом ANSI С.

Группа функций exec используется для выполнения другой программы. Эта другая программа, называемая процессом-потомком (child process), загружается поверх программы, содержащей вызов exec. Имя файла, содержащего процесс-потомок, задано с помощью параметра fname. Какие-либо аргументы, передаваемые процессу-потомку, задаются либо с помощью параметров от arg0 до argN, либо с помощью массива arg[]. Параметр envp[] должен указывать на строку окруже­ния. (Аргументы, на которые указывает argv в процессе-потомке.)


Если fname не содержит расширения или точки, то поиск сначала производится по имени файла. При неудаче добавляется расширение ЕХЕ и поиск повторяется. При неудаче использует­ся расширение СОМ и поиск опять повторяется. Если же расширение указывается, то осуществля­ется поиск только на предмет точного совпадения. Наконец, если имеется точка, но расширение не указано, то поиск осуществляется по левой части имени файла.

Точный способ исполнения процесса-потомка зависит от вызываемой версии функции exec. Можно представить себе функцию exec как имеющую различные суффиксы, задающие ее опера­ции. Суффикс может состоять из одного или двух символов.

Функции, имеющие в качестве суффикса р, ищут процесс-потомок в каталогах, заданных коман­дой PATH. Если же суффикс р отсутствует, то поиск осуществляется только в текущем каталоге.

Если задан суффикс l, то значит, аргументы передаются процессу-потомку индивидуально, а не массивом. Этот метод используется при передаче фиксированного числа аргументов. Следует обратить внимание, что последний аргумент должен быть NULL. (NULL определен в stdio.h.)

Суффикс v означает, что аргументы передаются процессу-потомку в массиве. Этот способ ис­пользуется тогда, когда заранее не известно, сколько аргументов будет передано процессу-потомку, либо же число аргументов может изменяться во время выполнения программы. Обычно конец массива обозначается нулевым указателем.

Суффикс е указывает, что процессу-потомку будет передана одна или более строк окружения. Параметр envp представляет собой массив указателей на строки. Каждая строка, на которую ука­зывает массив, должна иметь следующий вид: переменная_окружения = значение

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

Важно помнить, что файлы, открытые при вызове exec, являются также открытыми в програм­ме-потомке.

В случае успеха функция exec не возвращает значения. При неудаче возвращается значение —1, а переменная errno устанавливается равной одному из следующих значений:

Функция Function Обязательный заголовок Required header Необязательный заголовок Optional header
_execvp _execvp
_wexecvp _wexecvp
Макрос Значение
EACCESS Доступ к файлу процесса-потомка запрещен
EMFILE Слишком много открытых файлов
ENOENT Файл не найден
ENOEXEC Недействительный формат exec
ENOMEM Недостаточно свободной памяти для загрузки процесса-потомка

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

/* первый файл — родитель */
#include
#include

#include
int main ( void )
<
execl ( «test.exe» , «test.exe» , «hello» , «10» , NULL ) ;
return 0 ;
>

/* второй файл — потомок */
#include
#include
int main ( int argc , char * argv [ ] )
<
printf ( «This program is executed with these command line » ) ;
printf ( «arguments: » ) ;
printf ( argv [ 1 ] ) ;
printf ( » %d» , atoi ( argv [ 2 ] ) ) ;
return 0 ;
>

Как работает execlp, что за последний аргумент NULL?

2 ответа 2

я читал, что это какой-то указатель, никак к сожалению понять не могу

Попробуем прочитать man execlp вместе:

Параметр const char *arg и аналогичные записи в функциях execl, execlp, и execle подразумевают параметры arg0, arg1, . argn. Все вместе они описывают один или нескольких указателей на строки, заканчивающиеся NULL, которые представляют собой список параметров, доступных исполняемой программе. Первый параметр, по соглашению, должен указывать на имя, ассоциированное с файлом, который надо исполнить. Список параметров должен заканчиваться NULL.

Обратите внимание на последнее предложение. Оно означает, что NULL используется для индикации конца списка аргументов. Это один из общих механизмов сказать «больше агрументов нет» при вызове функций с переменным числом аргументов.

Кстати, вы понимаете, что при успешном запуске ls вот сюда вы никогда не попадёте?

Как execvp запустить команду?

Я знаю , execvp может быть использован для выполнения простых команд следующим образом :

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

Для определенности, скажем , есть команда , которая конкретно требует ввода , например , кошки. Если у меня есть текстовый файл text.txt , который содержит имя файла , ожидаемое для кошки и перенаправить стандартный ввод в файл поток файла, будет выход execle(cat,cat,NULL) или execvp(cat, arg) (очевидно , где ARG магазины cat и NULL ) приводит к выходу в консоли, что и cat /filename бы? Моя интуиция мне нужно прочитать файл и может быть разобрать его , чтобы сохранить аргументы в арг. Однако я хочу , чтобы убедиться.

Вот что происходит в execvp вызове:

  1. Ваша реализация Libc ищет в PATH , если это применимо, для файла , который должен быть выполнен. Большинство, если не все, команды в UNIX-подобные системы являются исполняемыми файлами. Что произойдет , если это не так ? Попробуй. Посмотрите , как Glibc это делает .
  2. Как правило, если исполняемый файл найден, то вызов execve будет. Части execve могут быть реализованы в LIBC или это может быть системный вызов (например , в Linux).
  3. Linux готовит программу выделения памяти для него, открыв его, планирование его исполнение, инициализирует структуру памяти, устанавливает свои аргументы и окружающую среду от предоставленных аргументов в execvp вызов, находит обработчик , подходящий для загрузки двоичного файла и устанавливает текущую задачу ( execvp абонент) не выполняется. Вы можете найти его реализацию здесь .

Все описанные выше действия соответствуют требованиям , установленным POSIX , которые описаны в соответствующих справочных страницах .

Что касается ваших вопросов:

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

Long-давно оболочка была очень ограничена и почти все команды UNIX были автономными исполняемыми файлами. Сейчас, в основном , для целей скорости некоторого подмножества UNIX команд реализуется внутри самой оболочки, эти команды называются builtins . Вы можете проверить все , что команда выполнена в вашей оболочке , как встроенные или не через type команду:

(Полный список встроенных команд с описаниями можно найти в man страницах в вашей оболочке , например , man bash-builtins или man builtin ) .

Но все-таки большинство команд до сих пор их исполняемый-аналог:

Так что в вашем конкретном случае, когда вы работаете:

Вы на самом деле заменить адресное пространство текущего процесса с адресным пространством (скорее всего) /bin/ls .

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

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

И добавить chmod +x к этому. После этого вы можете запустить его как исполняемый файл ( с помощью любой из exec функций или оболочки):

Из потому что это имеет недостаток , заключающийся в печати shebang себя файл , но все же интересно , чтобы сделать это в ядре =)

КСТАТИ. Проблема , что вы описали , если так часто , что есть специальный исполняемый файл под названием , xargs которое (в очень упрощенном объяснении) выполняет заданную программу в списке аргументов , переданных через стандартный ввод. Для получения дополнительной информации проконсультируйтесь с man xargs .

Для облегчения запоминания exec -семейства я часто использую следующую таблицу:

Так что в вашем случае execvp имеет имя файла, ARGV ( v ) и окружать ( е ). Тогда это пытается «угадать» путь к файлу ( так называемый полный путь) путем добавления filename (в вашем случае cat ) для каждого компонента пути в PATH до тех пор, пока найти путь с исполняемым файлом filename .

Гораздо больше информации о Что происходит под exec «ы капюшона ( в том числе наследственного материала) можно найти в Advanced программирования в UNIX среде (второе издание) У. Ричард Стивенс и Стивен А. Рий ака APUE2.
Если вы заинтересованы в UNIX внутренностей вероятно , вы должны прочитать его.

Изучение создания процесса UNIX


Анализ жизненного цикла процесса, запускаемого операционной системой UNIX

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

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

Основным компоновочным блоком управления этих программ является процесс. Процесс – это имя, присвоенное программе, выполняемой операционной системой. Если вы знаете команду ps , вам должен быть знаком список процессов, такой как в листинге 1.

Листинг1. Вывод команды ps

Для рассмотрения важны первые три колонки. В первой находится список пользователей,от имени которых работают процессы, во второй перечисляются ID процессов, в третьей — ID родительских процессов. Последняя колонка содержит описание процесса, как правило, имя запущенной программы. Каждому процессу присвоен идентификатор, который называется идентификатор процесса (PID). Также у процесса есть родитель, в большинстве случаев указывается PID процесса, который запустил данный процесс.

Существование родительского PID (PPID), означает, что один процесс создается другим процессом. Исходный процесс, который запускается в системе, называется init , и ему всегда присваивается PID 1. init — это первый действительный процесс, запускаумый ядром при загрузке. Основная задача init запуск всей системы. init и другие процессы с PPID 0 являются процессами ядра.

Использование системного вызова fork

Системный вызов fork(2) создает новый процесс. В листинге 2 показан fork используемый в простом примере C-кода.

Листинг 2. Простое применение fork(2)

Код в fork1.c просто вызывает fork и отображает целочисленный результат выполения fork через вызов printf . Делается только один вызов, но вывод отображается дважды. Это происходит потому, что новый процесс создается в рамках вызова fork . После вызова возвращаются два отдельных процесса. Это часто называют «вызванный единожды, возвращается дважды.»

Возвращаемые fork значения очень интересны. Одно из них — 0; другое – ненулевое значение. Процесс, который получает 0, называется порожденным процессом, а ненулевое значение достается исходному процессу, который является родительским процессом. Вы используете возвращаемые значения, для того чтобы определить, где какой процесс. Поскольку оба процесса возобновляют выполнение в одной и той же области, единственный возможный дифференциатор это возвращаемые значения fork .

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

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

Листинг 3. Более полный пример использования fork

В листинге 3 распечатываются PID распечатываются на каждом шаге, и код проверяет возвращаемые fork значения, для того чтобы определить, какой процесс родительский, а какой порожденный (дочерний). Сравнивая распечатанные PID, вы можете увидеть, что исходный процесс – это родительский процесс (PID 767), и порождаемый процесс (PID 768) знает, кто его родитель. Обратите внимание на то, как потомок находит своего родителя при помощи getppid , и как родитель использует результат fork для поиска своих потомков.

Теперь, когда вы разобрались с методом дублирования процессов, давайте рассмотрим, как выполнять разные процессы. fork — это только половина уравнения. Семейство системных вызовов exec запускает определенную программу.

Использование семейства системных вызовов exec

Задачей exec является замена текущего процесса на новый процесс. Отметьте использование слова заменить. Как только вы вызываете exec , текущий процесс завершается и начинается новый. Если вы хотите создать отдельный процесс, сначала вы должны вызвать fork , затем вызвать exec для новой программы в дочернем процессе. В листинге 4 показан этот сценарий.

Листинг 4. Запуск разных программ посредством соединения fork с exec

Код в листинге 4 прежде всего, определяет массив, первый элемент которого является путем к исполняемой программе, а остальные элементы представляют собой параметры командной строки. Массив заканчивается нулевым символом. После возврата от системного вызова fork дочерний процесс должен запустить новую программу с помощью execv .

При вызове execv в первую очередь получает указатель на строку с именем программы для запуска, а затем указатель на массив параметров, который вы задали ранее. Первый элемент массива фактически является именем программы, следовательно, параметры начинают перечисляться со второго элемента. Запомните, что порожденный процесс никогда не возвращается после вызова execv . Это означает, что выполняемый процесс заменяется на новый.

Есть и другие системные вызовы exec . Они отличаются способом приема параметров и вопросом относительно необходимости передачи переменных окружения. execv(2) — это один из самых простых способов замены текущего образа процесса, поскольку он использует массив с завершающим null-символом и не требует информации об окружении. Другие варианты: execl(2) , который принимает параметры в отдельные аргументы или execvp(2) , который также принимает массив переменных окружения с завершающим null-символом. Причем, не каждая операционная система поддерживает все варианты. Выбор зависит от платформы, способа программирования и от того, нужно ли вам определять какие-либо переменные окружения.

Что происходит с открытыми файлами, когда вызывается fork?

Когда процесс дублируется, ядро создает копии всех дескрипторов открытых файлов. Дескриптор файла — это целое число, которое является ссылкой на открытый файл или устройство, и используется для чтения и записи. Если открытие файла находится в программе перед fork , то что произойдет, если оба процесса попытаются читать или записывать? Перезапишет один из процессов данные другого? Будут прочитаны две копии файла? Эти вопросы изучаются в листинге 5, посредством открытия двух файлов — одного для чтения, другого для записи, а также при помощи одновременного чтения и записи родителем и потомком.

Листинг 5. Два процесса одновременно записывают и читают один и тот же файл.

Листинг 5 — это простая программа, открывающая файл и вызывающая fork . Каждый процесс использует для чтения один и тот же дескриптор файла (это просто текстовый файл с числами от 1 до 7), печатая то, что было прочитано вместе с PID. После прочтения строки PID записывается в выходной файл (out file). Цикл завершается, когда в файле больше не остается непрочитанных символов.

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

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

Смерть родителя или потомка

В какой-то момент процессы должны завершаться. Вопрос только в том, какой завершится первым: родитель или потомок.

Родительский процесс завершается раньше потомка

Если родительский процесс умирает раньше своих потомков, осиротевшие потомки должны знать, кто их родитель. Вспомните о том, что у каждого процесса есть родитель, и вы можете полностью отследить дерево процессов, начиная с PID 1, имеющего также название init . Когда родитель умирает, init усыновляет всех его потомков, как показано в листинге 6.

Листинг 6. Родительский процесс умирает раньше потомка

В этом примере родительский процесс вызывает fork , ждет две секунды и завершается. Порожденный процесс продолжается, распечатывая PID своего родителя в течение пяти секунд. Вы можете видеть, что когда родитель умирает, PPID изменяется на 1. Также интересно возвращение управления командному процессору. Поскольку порожденный процесс выполняется в фоне, как только родитель умирает, управление возвращается к командному процессору.

Потомок умирает раньше родителя

Листинг 7 описывает процесс противоположный листингу 6: смерть потомка раньше родителя. Для того чтобы лучше показать, что происходит, непосредственно из процесса ничего не распечатывается. Вместо этого, интересная информация находится в списке процессов.

Листинг 7. Порожденный процесс умирает раньше родительского

die2 выполняется в фоновом режиме, используя оператор & , после этого на экран выводится список процессов, отображая только выполняемый процесс и его потомков. PID 2934 – родительский процесс, PID 2935 – процесс, который создается и немедленно завершается. Несмотря на преждевременный выход, порожденный процесс все еще находится в таблице процессов, уже как умерший процесс, который еще называется зомби. Когда через 60 секунд родитель умирает, оба процесса завершаются.

Когда порожденный процесс умирает, его родитель информируется при помощи сигнала, который называется SIGCHLD . Точный механизм всего этого сейчас не имеет значения. Что действительно важно, так это то, что родитель должен как-то узнать о смерти потомка. С момента смерти потомка и до того момента как родитель получает сигнал, потомок находится в состоянии зомби. Зомби не выполняется и не потребляет ресурсов CPU; он только занимает пространство в таблице процессов. Когда родитель умирает, ядро наконец-то может убрать потомков вместе с родителем. Значит, единственный способ избавиться от зомби — это убить родителя. Лучший способ справиться с зомби – гарантировать, что они не окажутся на первом месте. Код в листинге 8 описывает обработчик сигналов, для работы с входящим сигналом SIGCHLD .

Листинг 8. Обработчик сигналов в действии

Листинг 8 немного сложнее, чем предыдущий пример, поскольку там есть функция sigset , которая устанавливает указатель функции на обработчик сигнала. Всякий раз, когда процесс получает обработанный сигнал, вызывается функция, заданная через sigset . Для сигнала SIGCHLD , приложение должно вызвать функцию wait(3c) для того, чтобы подождать завершения порожденного процесса. Поскольку процесс уже завершен, это необходимо для того, чтобы ядро получило подтверждение о смерти потомков. На самом деле, родителю следовало бы сделать больше, чем просто подтвердить сигнал. Ему следовало бы также очистить данные потомка.

После выполнения die3 , проверяется список процессов. Обработчик сигнала получает значение 18 ( SIGCHLD ), подтверждение о завершении потомка сделано, и родитель возвращается в состояние ожидания sleep(60) .

Краткие выводы

Процессы UNIX создаются, когда один процесс вызывает fork , который разделяет выполняемый процесс на два. После этого процесс может выполнить один из системных вызовов в семействе exec , который заменяет текущий образ на новый.


Когда родительский процесс умирает, всех его потомков усыновляет init , имеющий PID 1. Если потомок умирает раньше родителя, родительскому процессу передается сигнал, а потомок переходит в состояние зомби до тех пор, пока сигнал не подтвердится или родительский процесс не будет убит.

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

Ресурсы для скачивания

Похожие темы

  • Оригинал статьи Delve into UNIX process creation.
  • Учебное пособие YoLinux: Fork, Exec и Управление процессом: в этом пособии рассматриваются еще некоторые ошибки, которые могут возникнуть у процессов с комплексной структурой. В нем также имеется информация о других родственных системных вызовах.
  • fork : в этом документе подается больше информации о режимах работы, которые должны быть, когда есть процесс fork .
  • Threads подобные принципу fork , если вы хотите параллельно выполнять несколько задач. Примеры программирования для Linux®, Solaris и AIX® доступны.
  • Когда вы разобрались в работе fork , вы можете следить за отдельным выполнением процессов при помощи strace или truss . В этих двух статьях рассказывается, как это сделать:
    • Отдыхайте с strace и GDB Debugger Вильям Б. Зиммерли (William B. Zimmerly) (developerWorks, май 2006)
  • Инструментальные средства Системного Администрирования: Хитрости администрирования процесса (developerWorks, февраль 2006): в этой статье рассматриваются команды UNIX, касающиеся отображения обработки информации.

Комментарии

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

Child Processes

Стабильность: 2 – Стабильно

Модуль child_process предоставляет возможность создавать дочерние процессы способом, похожим, но не идентичным popen(3). Эта возможность изначально поставлялась с функцией child_process.spawn() :

По умолчанию пути для stdin , stdout и stderr установлены между родительским процессом Node.js и порожденным дочерним процессом. Возможно передавать потоки данных по этим путям с отсутствующей блокировкой. Следует заметить, однако, что некоторые программы используют буферизацию строк ввода-вывода. Это никак не влияет на Node.js, но может означать то, что данные, передаваемые дочернему процессу, не будут приняты сразу.

Метод child_process.spawn() создает дочерние процессы асинхронным способом, без блокирования цикла обработки событий Node.js. Функция child_process.spawnSync() реализует эквивалентный функционал сихронным способом, который блокирует цикл обработки событий до тех пор, пока порожденные процессы не будут закончены закрыты.

Для удобства, модуль child_process предоставляет синхронные или асинхронные альтернативы child_process.spawn() и child_process.spawnSync() . Следует заметить, что каждая из этих альтернатив реализуется в начале child_process.spawn() или child_process.spawnSync()

  • child_process.exec() : создает оболочку и запускает команду внутри этой оболочки, передавая stdout и stderr функции обратного вызова, если команда выполнена.
  • child_process.execFile() : похоже на child_process.exec() , за исключением того, что эта функция запускает команду непосредственно, минуя создание оболочки.
  • child_process.fork() : создает новый процесс Node.js и вызывает соответствующий модуль с предустановленным каналом связи IPC, который позволяет отправлять сообщения от родителя к дочернему процессу и в обратном порядке.
  • child_process.execSync() : сихронизированная версия child_process.exec() , которая блокирует цикл обработки событий Node.js.
  • child_process.execFileSync() : синхронизированная версия child_process.execFile() , которая блокирует цикл обработки событий Node.js.

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

Создание асинхронных процессов

Методы child_process.spawn() , child_process.fork() , child_process.exec() и child_process.execFile() работают по асинхронному программному шаблону, характерному прочим Node.js API.

Каждый метод возвращает экземпляр ChildProcess . Эти объекты реализуют Node.js EventEmitter API, позволяя родительскому процессу регистрировать функции, которые вызываются тогда, когда имеют место определенные события в жизненном цикле дочернего процесса.

Методы child_process.exec() и child_process.execFile() также позволяют определить опциональную функцию обратного вызова callback , которая вызывается после завершения дочернего процесса.

Создание .bat и .cmd файлов в Windows

Актуальность применения child_process.exec() или child_process.execFile() во многом зависит от платформы. На Unix-системах (Unix, Linux, OSX) child_process.execFile() может быть более эффективной, так как эта функция не создает оболочку. На Windows .bat и .cmd файлы не выполняются сами без терминала, и, следовательно, не могут быть запущены с помощью code>child_process.execFile() . При запуске на Windows, .bat и .cmd файлы могут запускаться с помощью child_process.spawn() c оболочкой shell , посредством child_process.exec() , или созданием cmd.exe , которому передаются .bat и .cmd в качестве аргументов (то, что делает функция оболочки и child_process.exec() ).

child_process.exec(command[, options][, callback])

  • command Команда запуска, аргументы разделяются пробелами
  • options
    • cwd Текущая рабочая директория дочернего процесса
    • env Пара среды ключ-значение
    • encoding (По умолчанию: ‘utf8’ )
    • shell Оболочка для выполнения команды (По умолчанию: ‘/bin/sh’ ) на Unix, ‘cmd.exe’ на Windows. Оболочка должна понимать -c на Unix и /s /c на Windows. На Windows парсинг командной строки должен быть совместим с ‘cmd.exe’
    • timeout (По умолчанию: 0 )
    • maxBuffer Наибольшее количество данных (в байтах), дозволенное stdout или stderr, при превышении которого дочерний процесс будет завершен. (По умолчанию: 200\ *1024 )
    • killSignal (По умолчанию: ‘SIGTERM’ )
    • uid Устанавливает идентификатор пользователя процесса
    • gid Устанавливает групповой идентификатор процесса
  • callback Вызывается на выходе, когда процесс завершен
    • error
    • stdout |
    • stderr ; |
  • Return

Создает оболочку, после чего выполняет command в этой оболочке, буферизируя все сгенерированные выходы (output).

Если есть функция callback , она вызывается с аргументами error, stdout, stderr . В случае успешного запуска, error будет null . В случае наличия ошибки, error будет экземпляром Error . Свойство error.code будет кодом завершения дочернего процесса, пока error.signal установлено на оповещение при завершении процесса. Любой код выхода, отличный от 0 считается за ошибку.

Аргументы stdout и stderr , передаваемые функции обратного вызова, будут содержать выходы дочернего процесса stdout и stderr. По умолчанию, Node.js декодирует выходы в UTF-8 и передает строки функции обратного вызова. Параметр encoding может быть использован для определения кодировки символов, что применяется для декодирования выходов stdout и stderr. Если encoding передается ‘buffer’ , вместо строк функции обратного вызова будут передаваться объекты буфера.

Аргумент options может быть передан как второй аргумент, чтобы кастомизировать создание процесса. По умолчанию:

Если timeout больше 0 , родительский процесс будет отправлять сигнал, определенный свойством killSignal (по умолчанию ‘SIGTERM’ ), в случае, когда дочерний процесс запущен дольше, чем задано в timeout .

Примечание: в отличие от системного вызова POSIX exec(3) , child_process.exec() не заменяет существующий процесс и использует оболочку для выполнения команды.


child_process.execFile(file[, args][, options][, callback])

  • file Имя выполняемого файла или путь к нему
  • args Массив строчных аргументов
  • options
    • cwd Текущая рабочая директория дочернего процесса
    • env Пара среды ключ-значение
    • encoding (По умолчанию: ‘utf8’ )
    • timeout (По умолчанию: 0 )
    • maxBuffer Наибольшее количество данных (в байтах), дозволенное stdout или stderr, при превышении которого дочерний процесс будет завершен. (По умолчанию: 200\ *1024 )
    • killSignal (По умолчанию: ‘SIGTERM’ )
    • uid Устанавливает идентификатор пользователя процесса
    • gid Устанавливает групповой идентификатор процесса
  • callback Вызывается на выходе, когда процесс завершен
    • error
    • stdout | ;
    • stderr |
  • Return

Функция child_process.execFile () подобна child_process.exec () за исключением того, что она не растягивает оболочку. Скорее всего, указанный исполняемый файл вызывает новый процесс, что делает его немного более эффективным, чем child_process.exec () .

Поддерживаются такие же настройки, как и в child_process.exec() . В случае, если оболочка не создана, поведение, типа перенаправления входа-выхода и глобализации файлов не поддерживается.

Аргументы stdout и stderr , передаваемые функции обратного вызова содержат выходы stdout и stderr, относящиеся к дочернему процессу. По умолчанию, Node.js декодирует выходы в UTF-8 и передает функции обратного вызова строку. Опция encoding может использоваться для того, чтобы задать кодировку для декодирования выходов stdout и stderr. Если параметр encoding — это ‘buffer’ , то вместо строк фукнции обратного вызова будут переданы объекты буфера.

child_process.fork(modulePath[, args][, options])

  • modulePath Модуль, запускаемый в дочернем процессе
  • args Перечень аргументов строки
  • options
  • cwd Текущая рабочая директория дочернего процесса
  • env Пары ключ-значение
  • execPath Выполняемая функция для создания дочернего процесса
  • execArgv Перечень аргументов строки, передаваемых выполняемой функции (по умолчанию: process.execArgv )
  • silent Если значение true , то stdin, stdout и stderr дочернего процесса будут передаваться к родительскому процессе, в противном случае они будут наследоваться от родительского процесса. См. опции ‘pipe’ и ‘inherit’ из child_process.spawn() для более детальной информации. (По умолчанию: false )
  • uid Устанавливает пользователя процесса
  • gid Устанавливает группу пользователей процесса
  • Return:

Метод child_process.fork() является частным случаем child_process.spawn() , который используется определенно для создания новых процессов Node.js. Подобно child_process.spawn() , в итоге возвращается объект ChildProcess. Возвращаемый ChildProcess имеет дополнительные каналы связи, которые позволяют сообщениям передаваться по обоим направлениям (вперед-назад) между родительским и дочерним процессом.

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

По умолчанию, child_process.fork() создает новые экземпляры Node.js, используя process.execPath из родительского процесса. Свойство execPath в объекте позволяет использовать альтернативный путь выполнения.

Процессы Node.js, зпапускаемые с помощью кастомного execPath сообщаются с родительским процессом через файловый дескриптор (fd), который определяется переменной окружения NODE_CHANELL_FD в дочернем процессе. Входом и выходом в этом дескрипторе являются объекты JSON, разделенные строкой.

Примечание: В отличие от fork(2) POSIX системного вызова, child_process.fork() не клонирует текущий процесс.

child_process.spawn(command[, args][, options])

  • command Команда запуска
  • args Перечень аргументов строки
  • options
  • cwd Текущая рабочая директория дочернего процесса
  • env Пары ключ-значение
  • stdio | Конфигурация stdio дочернего процесса
  • detached Подготавливает дочерний процесс к запуску независимо от родительского. Поведение определяется в зависимости от платформы (см. options.stdio )
  • uid Устанавливает пользователя процесса (см. setuid(2) )
  • gid Устанавливает группу пользователей процесса (см. setgid(2) )
  • shell | При значении true , запускает command внутри оболочки. На UNIX: ‘/bin/sh’ , Windows: ‘cmd.exe’ . Любая другая оболочка может быть определена как строка. Оболочка должна понимать свитч -c на UNIX и /s /c на Windows. По умолчанию: false (без оболочки)

  • Return:

Метод child_process.spawn() создает новый процесс, используя заданную command с аргументами командной строки args . Если это не указано, args по умолчанию содержит пустой массив.

Третий аргумент может использоваться для задания дополнительных опций и параметров с такими параметрами по умолчанию:

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

Используйте env , чтобы задать переменные окружения, которые будут доступны новому процессу. По умолчанию: process.env .

Пример запуска ls -lh /usr , с stdout , stderr и кодом выхода:

Пример: сложный способ запуска ps ax | grep ssh

Пример проверки на неудавшийся запуск:

options.detached

На Windows задание options.detached значения true делает возможным продолжение запуска дочернего процесса после того, как завершается родительский. Дочерний будет иметь собственное консольное окно. После запуска дочернего процесса, он не может быть прерван.

На других платформах, если options.detached задано значение true , дочерний процесс будет основным в группе новых процессов и сессий. Заметьте, что дочерний процесс может продолжать запуск после завершения родительского вне зависимости от того, разделены они или нет. Для более подробной информации см. setsid(2).

По умолчанию, родительский процесс должен ждать отделения от дочернего, чтобы завершиться. Чтобы предотвратить ожидание, следует использовать метод child.unref() . Выполнение этого метода исключит из родительского событийного цикла дочерний процесс, позволяя родителю завершиться отдельно от дочернего, несмотря на установленный между ними канал связи IPC.

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

Пример долговыполняемого процесса с отделением и игнорированием файловых дескрипторов stdio родительского процесса:

Альтернативный способ: перенаправление выхода дочернего процесса в файлы:

options.stdio

Опция options.stdio предназначена для конфигурирования каналов, настроенных между родительскими и дочерними процессами. По умолчанию, дочерние stdin, stdout и stderr перенаправляются на соответствующие стримы child.stdin, child.stdout и child.stderr в объекте ChildProcess. Это равнозначно приравниванию options.stdio к [‘pipe’, ‘pipe’, ‘pipe’] .

Для удобства options.stdio может быть одной из нижеприведенных строк:

  • ‘pipe’ – эквивалент [‘pipe’, ‘pipe’, ‘pipe’] (по умолчанию)
  • ‘ignore’ – эквивалент [‘ignore’, ‘ignore’, ‘ignore’]
  • ‘inherit’ – эквивалент [process.stdin, process.stdout, process.stderr] или [0,1,2]

В ином случае, значение options.stdio является массивом, где каждый индекс относится к файловому дескриптору дочернего процесса. Дескрипторы 0 , 1 , 2 ссылаются на stdin , stdout и stderr соответственно. Можно задать дополнительный дескриптор для создания дополнительных каналов между родителем и дочерним процессом. Значение будет одним из следующих:

  1. ‘pipe’ – создает канал между дочерним и родительским процессом. Конец канала со стороны рродителя является свойством объекта child_process как child.stdio[fd]. Каналы устанавливаются под дескрипторами 0–2 и могут ссылаться на child.stdin, child.stdout и child.stderr соответственно.
  2. ‘ipc’ – создает канал IPC для передачи сообщений/файловых дескрипторов от родителя к дочернему процессу и в обратном порядке. ChildProcess может иметь не более одного IPC stdio файлового дескриптора. Установка этой опции делает возможным выполнение метода child.send() . Если дочерний процесс записывает JSON сообщение в файловый дескриптор, обработчик события child.on(‘message’) будет запущен и в родительском процессе. Если дочерний является процессом Node.js, то наличие IPC канала позволяет выполняться методам process.send() , process.disconnect() , process.on(‘disconnect’) , и process.on(‘message’) в дочернем процессе.
  3. ‘ignore’ – заставляет Node.js игнорировать файловый дескриптор в дочернем процессе. Так как Node.js всегда оставляет открытыми дескрипторы 0–2 для порожденных им же процессов, установка дескриптора на ‘ignore’ заставит Node.js открыть /dev/null и назначить как дескриптор дочернего процесса.
  4. объект – расшаривает открытый для чтения или записи стрим, который ссылается на tty, файл, сокет или канал с дочерним процессом. Основной дескриптор стрима дублируется в дочерний процесс как файловый дескриптор, который соотносится с индексом массива stdio . Следует заметить, что стрим должен иметь базовый (основной) дескриптор (файловые стримы не имеют его, пока не запущено событие ‘open’ )
  5. Положительное число – целое значение, которое интерпретируется как файловый дескриптор, на данный момент открытый родительскому процессу. Он расшаривается на дочерний процесс так же, как и объекты .
  6. null , undefined – используюь значение по умолчанию. Для дескрипторов stdio 0, 1 и 2 (иными словами, stdin, stdout и stderr) создается канал. Для дескрипторов от 3 и больше по умолчанию задается ‘ignore’

Следует заметить, что, когда устанавливается канал IPC между родительским и дочерним процессом, и дочерний процесс является процессом Node.js, дочерний запускается с быссылочным IPC каналом ( unref() ), пока регистрируется обработчик событий для события process.on(‘disconnect’) . Это позволяет дочернему процессу нормально завершиться без привязки к открытому IPC каналу.

Создание синхронных процессов

Методы child_process.spawnSync() , child_process.execSync() и child_process.execFileSync() являются синхронными и будут блокировать цикл событий Node.js, приостанавливая выполнение любого добавочного кода, пока завершается созданный процесс.

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

child_process.execFileSync(file[, args][, options])

  • file Имя пути, по которому находится выполняемый файл для запуска
  • args Перечень аргументов строки
  • options
    • cwd Текущая рабочая директория дочернего процесса
    • input ; | Значение, которое будет передаваться как stdin созданному процессу (это значение будет перезаписывать stdio[0] )
    • stdio Конфигурация stdio дочернего процесса. По умолчанию: ‘pipe’
    • stderr по умолчанию является выходом stderr родительского процесса, если не задано stdio
    • env Пара среды ключ-значение
    • uid Устанавливает идентификатор пользователя процесса
    • gid Устанавливает групповой идентификатор процесса
    • encoding (По умолчанию: ‘utf8’ )
    • timeout (По умолчанию: undefined )
    • maxBuffer Наибольшее количество данных (в байтах), дозволенное stdout или stderr, при превышении которого дочерний процесс будет завершен.
    • killSignal (По умолчанию: ‘SIGTERM’ )
  • encoding (По умолчанию: ‘utf8’ )
  • Return | stdout из command
  • Метод child_process.execFileSync() в общем идентичен child_process.execFile(), за исключением того, что этот метод не возвращает значение, пока процесс полностью не закроется. Когда выйдет время timeout и будет отправлен killSignal , метод не возвращает ничего, пока процее полностью не будет завершен. Заметьте, что если дочерний процесс перехватывает сигнал SIGTERM , и при этом не завершается, родительский процесс будет приостановлен до тех пор, пока не завершится дочерний процесс.

    Если вышло время выполнения процесса, или он имеет непустой код выхода, этот метод будет выдавать ошибку. Объект Error будет содержать весь результат из child_process.spawnSync()

    child_process.execSync(command[, options])


    • file ; Имя пути, по которому находится выполняемый файл для запуска
    • args Перечень аргументов строки
    • options
      • cwd Текущая рабочая директория дочернего процесса
      • input | Значение, которое будет передаваться как stdin созданному процессу (это значение будет перезаписывать stdio[0] )
      • stdio Конфигурация stdio дочернего процесса. По умолчанию: ‘pipe’
      • stderr по умолчанию является выходом stderr родительского процесса, если не задано stdio
      • env Пара среды ключ-значение
      • shell ; Оболочка для выполнения команды. По умолчанию: на UNIX: ‘/bin/sh’ , Windows: ‘cmd.exe’ . Любая другая оболочка может быть определена как строка. Оболочка должна понимать свитч -c на UNIX и /s /c на Windows. На Windows парсинг командной строки должен быть совместим с cmd.exe
      • uid Устанавливает идентификатор пользователя процесса
      • gid Устанавливает групповой идентификатор процесса
      • encoding (По умолчанию: ‘utf8’ )
      • timeout (По умолчанию: undefined )
      • maxBuffer Наибольшее количество данных (в байтах), дозволенное stdout или stderr, при превышении которого дочерний процесс будет завершен.
      • killSignal (По умолчанию: ‘SIGTERM’ )
    • encoding ; (По умолчанию: ‘utf8’ )
  • Return ; | stdout из command
  • Метод child_process.execSync() в общем идентичен child_process.exec() , за исключением того, что этот метод не возвращает значение, пока процесс полностью не закроется. Когда выйдет время timeout и будет отправлен killSignal , метод не возвращает ничего, пока процесс полностью не будет завершен. Заметьте, что если дочерний процесс перехватывает сигнал SIGTERM , и при этом не завершается, родительский процесс будет приостановлен до тех пор, пока не завершится дочерний процесс.

    Если вышло время выполнения процесса, или он имеет непустой код выхода, этот метод будет выдавать ошибку. Объект Error будет содержать весь результат из child_process.spawnSync()

    child_process.spawnSync(command[, args][, options])

    • file Имя пути, по которому находится выполняемый файл для запуска
    • args Перечень аргументов строки
    • options
      • cwd Текущая рабочая директория дочернего процесса
      • input | Значение, которое будет передаваться как stdin созданному процессу (это значение будет перезаписывать stdio[0] )
      • stdio Конфигурация stdio дочернего процесса. По умолчанию: ‘pipe’
      • stderr по умолчанию является выходом stderr родительского процесса, если не задано stdio
      • env Пара среды ключ-значение
      • uid Устанавливает идентификатор пользователя процесса
      • gid Устанавливает групповой идентификатор процесса
      • encoding (По умолчанию: ‘utf8’ )
      • timeout ; В миллисекундах — максимальное время, в пределах которого может быть запущен процесс (По умолчанию: undefined )
      • maxBuffer Наибольшее количество данных (в байтах), дозволенное stdout или stderr, при превышении которого дочерний процесс будет завершен.
      • killSignal (По умолчанию: ‘SIGTERM’ )
    • encoding ; (По умолчанию: ‘utf8’ )
    • shell | При значении true , запускает command внутри оболочки. На UNIX: ‘/bin/sh’ , Windows: ‘cmd.exe’ . Любая другая оболочка может быть определена как строка. Оболочка должна понимать свитч -c на UNIX и /s /c на Windows. По умолчанию: false (без оболочки)
    • Return | stdout из command
      • pid Pid дочернего процесса
      • output Массив результатов из выхода stdio
      • stdout | Содержимое output[1]
      • stderr | Содержимое output[2]
      • status Код выхода дочернего процесса
      • signal Сигнал для прерывания дочернего процесса
      • error ; Ошибка, выдаваемая в случае, когда дочерний процесс неудачно запущен или время выполнения вышло

    Метод child_process.spawnSync() в общем идентичен child_process.spawn() , за исключением того, что этот метод не возвращает значение, пока процесс полностью не закроется. Когда выйдет время timeout и будет отправлен killSignal , метод не возвращает ничего, пока процесс полностью не будет завершен. Заметьте, что если дочерний процесс перехватывает сигнал SIGTERM , и при этом не завершается, родительский процесс будет приостановлен до тех пор, пока не завершится дочерний процесс.

    Если вышло время выполнения процесса, или он имеет непустой код выхода, этот метод будет выдавать ошибку. Объект Error будет содержать весь результат из child_process.spawnSync()

    Class: ChildProcess

    Экземплярами класса ChildProcess являются ивент-эмиттеры (EventEmitters), которые относятся к созданному дочернему процессу.

    Экземпляры ChildProcess не должны создаваться напрямую. Скорее, нужно использовать методы child_process.spawn(), child_process.exec(), child_process.execFile(), или child_process.fork() для их создания.

    Event: ‘close’

    • code Код выхода дочернего процесса, если процесс завершился самостоятельно
    • signal Сигнал для завершения дочернего процесса

    Событие ‘close’ запускается, когда потоки stdio дочернего процесса были закрыты. Это событие отличается от ‘exit’ , так как множественные процессы могут разделять одни и те же stdio потоки.

    Event: ‘disconnect’

    Событие ‘disconnect’ запускается после вызова метода child.disconnect() в родительском процессе или process.disconnect() в дочернем. После разъединения больше невозможно отправлять или получать сообщения , а также свойство child.connected будет false

    Event: ‘error’

    ‘error’ может быть запущено когда угодно:

    1. Когда процесс не может быть создан, или
    2. Когда процесс не может быть «убит», или
    3. Не удалась отправка сообщения дочернему процессу.

    Следует заметить, что событие ‘exit’ может или не может произойти после того, как выпала ошибка. Если вы ожидаете оба события, важно быть начеку по отношению к случайному многоразовому вызову функции обработчика.

    См. тажже child.kill() и child.send() .


    Event: ‘exit’

    • code Код выхода дочернего процесса, если процесс завершился самостоятельно
    • signal Сигнал для завершения дочернего процесса

    Событие ‘exit’ вызывается после завершения дочернего процесса. Если процесс окончен, конечным кодом выхода процесса является code , во всех других случаях — null . Если процесс был прекращен по сигналу, названием строки сигнала будет signal , в противном случае — null . Какое-то одно из этих двух значений всегда будет не null .

    Примечание: когда запускается событие ‘exit’ , потоки stdio дочернего процесса могут все еще быть открытыми.

    Также, следует заметить, что Node.js устанавливает обработчики сигналов для SIGINT и SIGTERM и процессы Node.js не будут прекращены немедленно по этим сигналам. Скорее, Node.js выполнит последовательность действий по очистке и затем перезапустит обработанные сигналы.

    Event: ‘message’

    • message парсируемый JSON объект или примитивное значение
    • sendHandle объект net.Socket или net.Server , также может быть незаданным

    Событие ‘message’ запускается, когда дочерний процесс использует process.send() для отправки сообщений.

    child.connected

    • После вызова child.disconnect становится false

    Свойство child.connected показывает, возможно ли еще отправлять и получать сообщения от дочернего процесса. Когда child.connected — false , это означает, что обмен сообщениями с дочерним процессом больше невозможен.

    child.disconnect()

    Закрывает IPC канал между родителем и дочерним процессом, позволяя дочернему процессу звершиться без препятствий при отсутствии работающих соединений. После вызова этого метода, свойства child.connected и process.connected в родительском и дочернем процессе соответственно будут установлены на false , и дальнейший обмен сообщениями между процессами больше не будет возможным.

    Событие ‘disconnect’ запускается, когда нет получения сообщений. Чаще всего оно срабатывает сразу после вызова child.disconnect .

    Следует заметить, что когда дочерний процесс является экземпляром Node.js (т.е. создан с помощью chuld_process.fork()), метод process.disconnect() может быть вызван в дочернем процессе, чтобы закрыть IPC канал.

    child.kill([signal])

    Методы child.kill() посылают сигнал дочернему процесс. Если аргументы не заданы, то процессу будет по умолчанию отправлен сигнал ‘SIGTERM’ . См. signal(7) для просмотра списка доступных сигналов.

    Объект ChildProcess может вызывать событие ‘error’, если сигнал не может быть получен. Отправка сигнала дочернему процессу, который уже завершен, не рассматривается как ошибка, но может повлечь непредвиденные последствия. Конкретнее, если идентификатор процесса (PID) был переназначен на другой процесс, сигнал может быть получен этим процессом вместо заданного, что может иметь неожиданный результат.

    Обратите внимание, что пока функция имеет имя kill , сигнал, передаваемый дочернему процессу, не может действительно прекратить процесс.

    Также: на Linux дочерний процесс (или процессы) не могут быть прекращены, пока есть команда kill для их родительских процессов. Такое может случиться при запуске нового процесса в оболочке или с использованием опции shell в ChildProcess , как, например:

    child.pid

    • Целое число

    Возвращает идентификатор дочернего процесса (PID).

    child.send(message[, sendHandle[, options]][, callback])

    • message
    • sendhandle
    • options
    • callback
    • Return:

    Когда установлен IPC канал между родителем и дочерним процессом (при использовании child_process.fork()), можно использовать метод child.send() для отправки сообщений дочернему процессу. Если дочерний процесс является экземпляром Node.js, эти сообщения могут быть получены с помощью события process.on(‘message’) .

    Скрипт для родителя в качестве примера:

    И дочерний скрипт, sub.js , который может быть таким:

    Дочерние процессы Node.js могут использовать метод process.send() или свой собственный, что позволяет дочернему процессу отправлять сообщения в обратном порядке, к родительскому процессу.

    Особый случай — отправка сообщения . Все сообщения, содержащие приставку NODE_ , являются свойствами cmd . Предусматривается, что эти сообщения будут получены для ядра Node.js без отправки их событием process.on(‘message’). Такие сообщения, скорее, отправляются посредством события process.on(‘internalMessage’) и получаются непосредственно Node.js. Приложениям следует избегать использования таких сообщений или их просмотра в событиях ‘internalMessage’ , так как они могут изменяться без предупреждения.

    Опциональный аргумент sendHandle , который может быть передан child.send() , существует для

    передачи TCP сервера или объекта сокета дочернему процессу. Дочерний процесс может получить объект как второй аргумент, переданный функции обратного вызова, что была зарегистрирована в событии process.on(‘message’). Любые полученные и отправленные в буфер данные сокета не будут отправляться дочернему процессу.

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

    • keepOpen – значение boolean , которое может использоваться при передаче экземпляров new.Socket . Если оно true , сокет остается открытым в процессе отправки. По умолчанию: false .

    callback – это функция, которая вызывается после того, как сообщение было отправлено, но до того, как дочерний процесс его получит. Функция вызывается с одним единственным аргументом: null в случае удачного запуска и объектом Error в противном случае.

    Если нет функции callback и сообщение не может быть отправлено, событие ‘error’ выпоняется объектом ChildProcess . Такое может произойти, например, когда дочерний процесс уже завершился.

    child.send() будет возвращать false в случае, когда закрыт канал, а также если бэклог неотправленных сообщений превышает порог, выше которого нецелесообразна отправка сообщений в дальнейшем.В ином случае, метод возвращает true . Функцию callback можно использовать для реализации контроля потоков.

    Пример: отправка объекта сервера

    Аргумент sendHandle можно использовать, например, для передаче обработчика объекта TCP сервера дочернему процессу (как показано ниже):

    Дочерний процесс будет получать этот объект сервера таким образом:

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

    В то время, как вышеприведенный пример иллюстрирует использование сервера, созданного с помощью модуля net , модуль dgram использует точно тот же рабочий процесс, за исключением просмотра события ‘message’ вместо ‘connection’ и использования server.bind() вместо server.listen() . Это, однако, на данный момент поддерживается только UNIX платформами.

    Пример: отправка объекта сокета

    Похожим образом аргумент sendHandler может быть использован для передачи обработчика сокета дочернему процессу. Пример ниже показывает создание двух «детей», каждый из которых обрабатывает соединения с приоритетами «normal» и «special»:

    child.js будет получать обработчик сокета как второй аргумент, передаваемый событию функции обратного вызова:

    После того, как сокет был передан дочернему процессу, родитель больше не имеет возможности отслеживать, где сокеты уничтожаются. Для определения этого, свойство .connections становится null . Рекомендуется не использовать .maxConnections , если попадается.

    Примечание: эта функция использует внутри JSON.stringify() для сериализации сообщений.

    child.stderr

    Readable Stream (открытый для чтения стрим), что представляет stderr дочернего процесса.

    Если дочерний процесс был создан с stdio[2] , установленным на что угодно, кроме ‘pipe’ , значит, значение по умолчанию будет undefined .

    child.stderr является «союзником» child.stdio[2] . Оба свойства ссылаются на одно и то же значение.

    child.stdin

    Writable Stream (открытый для записи стрим), что представляет stdin дочернего процесса.

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

    Если дочерний процесс был создан с stdio[0] , установленным на что угодно, кроме ‘pipe’ , значит, значение по умолчанию будет undefined .

    child.stdin является «союзником» child.stdio[0] . Оба свойства ссылаются на одно и то же значение.

    child.stdio

    «Разбросанный» массив каналов (pipes), ведущих к дочернему процессу, который ссылается на позиции опций stdio, переданных child_process.spawn(), которым было задано значение ‘pipe’ . Следует заметить, что child.stdio[0] , child.stdio[1] , и child.stdio[2] – то же самое, что и child.stdin , child.stdout , и child.stderr , соответственно.

    В следующем примере демонстрируется, как только файловый дескриптор дочернего процесса 1 (stdout) конфигурируется как канал, так, что только родительский child.stdio[1] является стримом, все остальные значения в массиве null .

    child.stdout

    Readable Stream (открытый для чтения стрим), что представляет stdout дочернего процесса.

    Если дочерний процесс был создан с stdio[1] , установленным на что угодно, кроме ‘pipe’ , значит, значение по умолчанию будет undefined .

    child.stdout является «союзником» child.stdio[1] . Оба свойства ссылаются на одно и то же значение.

    maxBuffer и Юникод

    Важно помнить, что опция maxBuffer задает самое больше число октетов, допустимых в stdout и stderr . Если это значение превосходит заданное, дочерний процесс прерывается. Это практически влияет на выходы, которые включают в себя мультибайтовые кодировки символов, такие как UTF-8 или UTF-16. Например, следующий пример выводит 13 закодированных в UTF-8 октетов на stdout , хотя мы видим только 4 символа.

    Почему exec запускает процесс, который не работает?

    Если выполнить в терминале команду:

    То скрипт выполнится успешно, выведется его pid и он будет висеть в процессах, выполняя свою задачу.

    Но если тоже самое выполнить в другом php скрипте через функцию exec, то скрипт /path/to/file.php также будет висеть в процессах, как-будто выполняет свою задачу, но это не так.

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

    9.1.4.2. Функции-оболочки: execl() и др.

    9.1.4.2. Функции-оболочки: execl() и др.

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

    int execl(const char *path, const char *arg, . )

    Первый аргумент, path , является путем к исполняемому файлу. Последующие аргументы, начиная с arg , являются отдельными элементами, которые должны быть помещены в argv . Как и ранее, явным образом должен быть включен argv[0] . Вы должны в качестве последнего аргумента передать завершающий указатель NULL , чтобы execl() смогла определить, где заканчивается список аргументов. Новая программа наследует любые переменные окружения, которые находятся в переменной environ .

    int execlp(const char *file, const char *arg, . )

    Эта функция подобна execl() , но она имитирует механизм поиска команд оболочки, разыскивая file в каждом каталоге, указанном в переменной окружения PATH . Если file содержит символ / , этот поиск не осуществляется. Если PATH в окружении не присутствует, execlp() использует путь по умолчанию. В GNU/Linux по умолчанию используется » :/bin:/usr/bin «, но в других системах может быть другое значение. (Обратите внимание, что ведущее двоеточие в PATH означает, что сначала поиск осуществляется в текущем каталоге.)

    Более того, если файл найден и имеет право доступа на исполнение, но не может быть исполнен из-за того, что неизвестен его формат, execlp() считает, что это сценарий оболочки и запускает оболочку с именем файла в качестве аргумента.

    int execle(const char *path, const char *arg, .

    char *const envp[])

    Эта функция также подобна execl() , но принимает дополнительный аргумент, envp , который становится окружением новой программы. Как и в случае с execl() , вы должны для завершения списка аргументов поместить перед envp указатель NULL .

    Вторая группа функций-оболочек принимает массив в стиле argv :

    int execv(const char *path, char *const argv[])

    Эта функция подобна execve() , но новая программа наследует любое окружение, которое находится в переменной environ текущей программы.

    int execvp(const char *file, char *const argv[])

    Эта функция подобна execv() , но она осуществляет такой же поиск в PATH , как и функция execlp() . Она также переходит на исполнение сценария оболочки, если найденный файл не может быть исполнен непосредственно.

    В табл. 9.1 подведены итоги для шести функций exec() .

    Таблица 9.1. Сводка семейства функций exec() по алфавиту

    Функция Поиск пути Окружение пользователя Назначение
    execl() ? Исполняет список аргументов.
    execle() Исполняет список аргументов с окружением.
    execlp() ? ? Исполняет список аргументов с поиском пути
    execv() ? Исполняет с argv
    execve() Исполняет с argv и окружением (системный вызов).
    execvp() ? ? Исполняет с argv и с поиском пути

    Функций execlp() и execvp() лучше избегать, если вы не знаете, что переменная окружения PATH содержит приемлемый список каталогов.

    Илон Маск рекомендует:  Диагностические сообщения компилятора delphi
    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL