Далее приведен фрагмент типичного программного кода, использующего вызов 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.
Читать дальше