Далее приведен фрагмент типичного программного кода, использующего вызов fork
:
pid_t new_pid;
new_pid = fork();
switch(new_pid) {
case -1:
/* Ошибка */
break;
case 0:
/* Мы — дочерний процесс */
break;
default:
/* Мы — родительский процесс */
break;
}
Выполните упражнение 11.3.
Упражнение 11.3. Системный вызов fork
Давайте рассмотрим простой пример fork1.с:
#include
#include
#include
#include
int main() {
pid_t pid;
char* message;
int n;
printf("fork program starting\n");
pid = fork();
switch(pid) {
case -1:
perror("fork failed");
exit(1);
case 0:
message = "This is the child";
n = 5;
break;
default:
message = "This is the parent";
n = 3;
break;
}
for (; n > 0; n--) {
puts(message);
sleep(1);
}
exit(0);
}
Эта программа выполняет два процесса. Дочерний процесс создается и выводит пять раз сообщение. Исходный процесс (родитель) выводит сообщение только три раза. Родительский процесс завершается до того, как дочерний процесс выведет все свои сообщения, поэтому в вывод попадает очередное приглашение командной оболочки.
$ ./fork1
fork program starting
This is the child
This is the parent
This is the parent
This is the child
This is the parent
This is the child
$ This is the child
This is the child
Как это работает
Когда вызывается fork
, эта программа делится на два отдельных процесса. Родительский процесс идентифицируется ненулевым возвращаемым из fork
значением и используется для задания количества сообщений, выводимых с интервалом в одну секунду.
Когда вы запускаете дочерний процесс с помощью вызова fork
, он начинает жить собственной жизнью и выполняется независимо. Иногда вам нужно знать, когда закончился дочерний процесс. Например, в предыдущей программе родительский процесс завершается раньше дочернего, и вы получаете слегка беспорядочный вывод, потому что дочерний процесс продолжает выполняться. Вы можете с помощью системного вызова wait
заставить родительский процесс дождаться завершения дочернего процесса перед своим продолжением.
#include
#include
pid_t wait(int *stat_loc);
Системный вызов wait
заставляет родительский процесс сделать паузу до тех пор, пока один из его дочерних процессов не остановится. Вызов возвращает PID дочернего процесса. Обычно это дочерний процесс, который завершился. Сведения о состоянии позволяют родительскому процессу определить статус завершения дочернего процесса, т.е. значение, возвращенное из функции main
или переданное функции exit
. Если stat_loc
не равен пустому указателю, информация о состоянии будет записана в то место, на которое указывает этот параметр.
Интерпретировать информацию о состоянии процесса можно с помощью макросов, описанных в файле sys/wait.h и приведенных в табл. 11.2.
Таблица 11.2
Макрос |
Описание |
WIFEXITED(stat_val) |
Ненулевой, если дочерний процесс завершен нормально |
WEXITSTATUS(stat_val) |
Если WIFEXITED ненулевой, возвращает код завершения дочернего процесса |
WIFSIGNALED(stat_val) |
Ненулевой, если дочерний процесс завершается неперехватываемым сигналом |
WTERMSIG(stat_val) |
Если WIFSIGNALED ненулевой, возвращает номер сигнала |
WIFSTOPPED(stat_val) |
Ненулевой, если дочерний процесс остановился |
WSTOPSIG(stat_val) |
Если WIFSTOPPED ненулевой, возвращает номер сигнала |
Выполните упражнение 11.4.
Упражнение 11.4. Системный вызов wait
В этом упражнении вы слегка измените программу, чтобы можно было подождать и проверить код состояния дочернего процесса. Назовите новую программу wait.c.
Читать дальше