7.6 KiB
Лабораторная работа №2
Задание 1
В основной программе переменной x присвоить значение 100, а затем вызвать fork(). Каково значение x в порождённом процессе? Что происходит, когда основной и порожденный процессы меняют значение x?
Значение x
в порождённом процессе равно 100, так как при вызове fork()
память
процесса копируется в форк.
Изменение значения x
в порождённом или основном процессе никак не влияет на
значение в соседнем, так как форки не имеют общую память.
Задание 2
Порожденный процесс, созданный с помощью fork(), должен напечатать “hello”; основной - “goodbye”. Нужно обеспечить, чтобы порожденный процесс печатал первым без использования wait() в основном.
Это можно реализовать по меньшей мере двумя способами:
sysctl -w kernel.sched_child_runs_first=1
- "Поднять" SIGSTOP в основном процессе перед выводом
goodbye
, а в форке послать родительскому процессу SIGCONT после выводаhello
. SIGCHLD
?
В данной лабораторной работе был использован второй способ.
Задание 3
Сначала вызывается fork(), а затем какой-либо вариант exec() (execl(), execle(), execlp(), execv(), execvp(), и execvpe()) для вызова /bin/ls. Для чего предусмотрено столько много вариантов exec()?
Постфиксы в exec-функциях имеют следующие значения:
v
— передача аргументов программе нуль-терминированным массивом;l
— передача аргументов программе через переменные аргументы функции (variadic arguments), последний аргумент должен быть NULL;p
— передача программе текущей переменной PATH;e
— передача программе собственных переменных окружения массивом строк видаvar=value
Задание 4
В основной программе использовать wait() для того, чтобы дождаться завершения порожденного процесса? Что возвращает wait()? Что произойдет, если использовать wait() в порожденном процессе? Использовать waitpid() вместо of wait(). Когда использование waitpid() целесообразно?
wait()
возвращает -1
при ошибке (код ошибки при этом лежит в errno
),
0
, если передан флаг WNOHANG
и ни один дочерний процесс к моменту возврата управления
не был завершён, и PID завершённого процесса в остальных случаях.
Если вызвать wait()
в процессе, не порождающем другие, управление тут же будет возвращено,
а функция вернёт -1
.
waitpid()
целесообразно использовать, когда необходимо дождаться завершения процесса с определённым
PID, либо одного из процессов из определённой группы (для этого в waitpid()
в качестве pid передаётся
-pgid). -1
обозначает ожидание любого дочернего процесса, а 0
обозначает ожидание любого дочернего
процесса, чей pgid равен таковому у текущего процесса.
Также у wait()
и waitpid()
есть аргумент int *status
, куда будет записан статус дочернего
процесса. Для получения информации из этого буфера, нужно использовать следующие макросы:
WIFEXITED(status)
не равно нулю, если дочерний процесс успешно завершился.
WEXITSTATUS(status)
возвращает восемь младших битов значения, которое вернул завершившийся дочерний процесс. Эти биты
могли быть установлены в аргументе функции exit() или в аргументе оператора return функции main().
Этот макрос можно использовать, только если WIFEXITED вернул ненулевое значение.
WIFSIGNALED(status)
возвращает истинное значение, если дочерний процесс завершился из-за необработанного сигнала.
WTERMSIG(status)
возвращает номер сигнала, который привел к завершению дочернего процесса. Этот макрос можно использовать,
только если WIFSIGNALED вернул ненулевое значение.
WIFSTOPPED(status)
возвращает истинное значение, если дочерний процесс, из-за которого функция вернула управление, в настоящий
момент остановлен; это возможно, только если использовался флаг WUNTRACED или когда подпроцесс отслеживается
(см. ptrace(2)).
WSTOPSIG(status)
возвращает номер сигнала, из-за которого дочерний процесс был остановлен. Этот макрос можно использовать, только
если WIFSTOPPED вернул ненулевое значение.
Некоторые версии Unix (например Linux, Solaris, но не AIX, SunOS) также определяют макрос WCOREDUMP(status) для
проверки того, не вызвал ли дочерний процесс ошибку ядра. Используйте это только в структуре
#ifdef WCOREDUMP ... #endif.
Задание 7
Программа порождает процесс и в нем закрывает стандартный вывод (STDOUT FILENO). Что произойдет, если осуществить вызов printf() для того, чтобы что-то вывести в основном и дочернем процессах?
Закрытие файлового дескриптора stdout в дочернем процессе никак не повлияет на родителя. Но в форке после закрытия
stdin вызов printf()
вернёт -1
, а в errno
будет лежать значение EBADF
, обозначающее Bad file descriptor
.