++sigusr1_count;
}
int main() {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = &handler
sigaction(SIGUSR1, &sa, NULL);
/* далее идет основной текст. */
/* ... */
printf("SIGUSR1 was raised %d times\n", sigusr1_count);
return 0;
}
3.4. Завершение процесса
Обычно процесс завершается одним из двух способов: либо выполняющаяся программа вызывает функцию exit()
main()
заканчивается. У каждого процесса есть код завершения — число, возвращаемое родительскому процессу. Этот код передается в качестве аргумента функции exit()
или возвращается функцией main()
.Возможно также аварийное завершение процесса, в ответ на получение сигнала. Таковыми могут быть, например, упоминавшиеся выше сигналы SIGBUS
SIGSEGV
и SIGFPE
. Есть сигналы, явно запрашивающие прекращение работы процесса. В частности, сигнал SIGINT
посылается, когда пользователь нажимает SIGTERM
kill
по умолчанию. Если программа вызывает функцию abort()
, она посылает сама себе сигнал SIGABRT
. Самый "могучий" из всех сигналов — SIGKILL
: он приводит к безусловному уничтожению процесса и не может быть ни блокирован, ни обработан.Любой сигнал можно послать с помощью команды kill
SIGKILL
, воспользуйтесь следующей командой:% kill -KILL
Для отправки сигнала из программы предназначена функция kill()
kill
соответствует сигнал SIGTERM
). Например, если переменная child_pid
содержит идентификатор дочернего процесса, то следующая функция, вызываемая из родительского процесса, вызывает завершение работы потомка:kill(child_pid, SIGTERM);
Для использования функции kill()
и
.По существующему соглашению код завершения указывает на то, успешно ли выполнилась программа. Нулевой код говорит о том, что все в порядке, ненулевой код свидетельствует об ошибке. В последнем случае конкретное значение кода может подсказать природу ошибки. Подобным образом функционируют все компоненты GNU/Linux. Например, на это рассчитывает интерпретатор команд, когда в командных сценариях вызовы программ объединяются с помощью операторов &&
||
(логическое сложение) Таким образом, функция main()
должна явно возвращать 0 при отсутствии ошибок.Помните о следующем ограничении: несмотря на то что тип параметра функции exit()
main()
, равен int
, операционная система Linux записывает код завершения лишь в младший из четырех байтов. Это означает, что значение кода должно находиться в диапазоне от 0 до 127. Коды, значение которых больше 128, интерпретируются особым образом: когда процесс уничтожается вследствие получения сигнала, его код завершения равен 128 плюс номер сигнала.3.4.1. Ожидание завершения процесса
Читатели, запускавшие программу fork-exec
ls
часто появляется после того, как основная программа уже завершила свою работу. Это связано с тем, что дочерний процесс, в котором выполняется команда ls
, планируется независимо от родительского процесса. Linux — многозадачная операционная система, процессы в ней выполняются одновременно, поэтому нельзя заранее предсказать, кто — предок или потомок — завершится раньше.Но бывают ситуации, когда родительский процесс должен дождаться завершения одного или нескольких своих потомков. Это можно сделать с помощью функций семейства wait()
3.4.2. Системные вызовы wait()