/* передается свое окружение */
execv("/bin/ps", ps_argv);
execvp("ps", ps_argv);
execve("/bin/ps", ps_argv, ps_envp);
А теперь выполните упражнение 11.2.
Упражнение 11.2. Функция execlp
Давайте изменим пример и используем вызов execlp:
#include
#include
#include
int main() {
printf("Running ps with execlp\n");
execlp("ps", "ps", "ax", 0);
printf("Done.\n");
exit(0);
}
Когда вы выполните эту программу, рехес.с, то получите обычный вывод команды ps, но без сообщения Done. Кроме того, обратите внимание на то, что в выводе нет процесса с именем рехес:
$ ./рехес
Running ps with execlp
PID TTY STAT TIME COMMAND
1 ? S 0:03 init [5]
...
1262 pts/1 Ss 0:00 /bin/bash
1273 pts/2 S 0:00 su -
1274 pts/2 S+ 0:00 -bash
1463 pts/1 SN 0:00 oclock
1465 pts/1 S 0:01 emacs Makefile
1514 pts/1 R+ 0:00 ps ax
Как это работает
Программа выводит первое сообщение и затем вызывает функцию execlp, которая ищет каталоги, заданные в переменной окружения PATHдля обнаружения программы ps. Далее она выполняет команду вместо программы рехес, запустив ее так, как будто вы ввели команду командной оболочки
$ ps ax
Когда psзавершается, вы получаете новую строку приглашения командной оболочки. Возврата в программу рехесне происходит, поэтому второе сообщение не выводится. PID нового процесса тот же, что и у исходного, то же самое можно сказать о PID родительского процесса и значении nice. В сущности, происходит следующее: выполняющаяся программа запустила на выполнение новый код и новый исполняемый файл, заданный в вызове функции exec.
Существует ограничение для общего размера списка аргументов и окружения процесса, запускаемого функциями exec. Оно задается в переменной ARG_MAXи в системах Linux равно 128 Кбайт. В других системах может задаваться меньший предельный размер, что способно порождать проблемы. Стандарт POSIX гласит, что ARG_MAXдолжна быть не менее 4096 байтов.
Функции exec, как правило, не возвращаются в программу до тех пор, пока не возникла ошибка, в этом случае задается переменная errnoи функция execвозвращает -1.
Новые процессы, запущенные exec, наследуют многие свойства исходного процесса. В частности, открытые файловые дескрипторы остаются открытыми в новом процессе, пока не установлен их флаг FD_CLOEXEC(close on exec) (подробную информацию см. в описании системного вызова fcntlв главе 3 ). Любые открытые в исходном процессе потоки каталогов закрываются.
Дублирование образа процесса
Для применения процессов, выполняющих несколько функций одновременно, можно либо использовать потоки, обсуждаемые в главе 12, либо создавать в программе полностью отдельный процесс, как делает init, вместо замещения текущего потока исполнения, как в случае применения функции exec.
Создать новый процесс можно с помощью вызова fork. Системный вызов дублирует текущий процесс, создавая новый элемент в таблице процессов с множеством атрибутов, таких же как у текущего процесса. Новый процесс почти идентичен исходному, выполняет тот же программный код, но в своем пространстве данных, окружении и со своими файловыми дескрипторами. В комбинации с функциями execвызов fork— все, что вам нужно для создания новых процессов.
#include
#include
pid_t fork(void);
Как видно из рис. 11.2, вызов forkвозвращает в родительский процесс PID нового дочернего процесса. Новый процесс продолжает выполнение так же, как и исходный, за исключением того, что в дочерний процесс вызов forkвозвращает 0. Это позволяет родительскому и дочернему процессам определить, "кто есть кто".
Рис. 11.2
Если вызов forkзавершается аварийно, он возвращает -1. Обычно это происходит из-за ограничения числа дочерних процессов, которые может иметь родительский процесс ( CHILD_MAX), в этом случае переменной errnoбудет присвоено значение EAGAIN. Если для элемента таблицы процессов недостаточно места или не хватает виртуальной памяти, переменная errnoполучит значение ENOMEM.
Читать дальше