|
136 |
|
Подразумеваемая реакция - аварийное завершение и создание |
|
файла с образом памяти процесса. |
SIGSTOP |
Остановка выполнения (этот сигнал нельзя перехватить для |
|
обработки или проигнорировать). |
|
Подразумеваемая реакция - остановка процесса. |
SIGTERM |
Сигнал терминирования. |
|
Подразумеваемая реакция - аварийное завершение процесса. |
SIGTSTP |
Сигнал остановки, поступивший с терминала. |
|
Подразумеваемая реакция - остановка процесса. |
SIGTTIN |
Попытка чтения из фонового процесса. |
|
Подразумеваемая реакция - остановка процесса. |
SIGTTOU |
Попытка записи из фонового процесса. |
|
Подразумеваемая реакция - остановка процесса. |
SIGUSR1, |
Определяемые пользователем сигналы. |
SIGUSR2 |
Подразумеваемая реакция - аварийное завершение процесса. |
SIGPOLL |
Опрашиваемое событие. |
|
Подразумеваемая реакция - аварийное завершение процесса. |
SIGPROF |
Срабатывание таймера профилирования. |
|
Подразумеваемая реакция - аварийное завершение процесса. |
SIGSYS |
Некорректный системный вызов. |
|
Подразумеваемая реакция - аварийное завершение и создание |
|
файла с образом памяти процесса. |
SIGTRAP |
Попадание в точку трассировки/прерывания. |
|
Подразумеваемая реакция - аварийное завершение и создание |
|
файла с образом памяти процесса. |
SIGURG |
Высокоскоростное поступление данных в сокет. |
|
Подразумеваемая реакция - игнорирование. |
SIGVTALRM |
Срабатывание виртуального таймера. |
|
Подразумеваемая реакция - аварийное завершение процесса. |
SIGXCPU |
Исчерпан лимит процессорного времени. |
|
Подразумеваемая реакция - аварийное завершение и создание |
|
файла с образом памяти процесса. |
SIGXFSZ |
Превышено ограничение на размер файлов. |
|
Подразумеваемая реакция - аварийное завершение и создание |
|
файла с образом памяти процесса. |
В целом, технология использования сигналов достаточно сложна и требует знания многих аспектов работы ОС.
Далее, мы рассмотрим простой пример, предполагающий, что дочерние процессы могут быть остановлены по тем или иным причинам, например внешним воздействием. В таком случае, родительский процесс может бесконечно долго ожидать их
137
завершения.
Если остановка дочернего процесса вызвана получением соответствующего сигнала, то родительский процесс может узнать об этом с помощью системного вызова waitpid(...).
На листинге 3.7 представлена программа, в которой:
•родительский процесс, в цикле, создает пять дочерних процессов, после чего начинает ожидать их завершение, отслеживая остановки по получению сигналов;
•каждый дочерний процесс, после небольшого тайм-аута, посылает себе сигнал SIGSTOP, останавливая свою работу;
•родительский процесс обнаруживает остановку дочернего процесса по сигналу и сам посылает сигнал SIGCONT, который дает возможность дочернему процессу завершить свою работу.
Листринг 3.7 — Пример перезапуска дочерних процессов, остановленных сигналом
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h>
int main(void) {
puts("Проект lab9.7 ..."); pid_t pid, cpid;
int i, status=0xAAAA;
puts("Запуск пяти дочерних процессов:"); for (i=0; i<5; i++) {
pid = fork(); if (pid > 0) {
printf(" Родителский процесс: Запустил ДП%i с pid = %i\n", i, pid);
}else{
sleep(i + 3);
printf(" ДП%i pid=%i: останавливаюсь сигналом SIGTOP\n", i, getpid()); raise(SIGSTOP);
printf(" ДП%i: Завершаюсь со статусом = %i\n", i, i); exit(i);
}
}
sleep(1);
puts("Ожидание завершения дочерних процессов:"); while((cpid = waitpid(-1, &status, WUNTRACED)) > 0) {
if (WIFSTOPPED(status)) {
printf(" РП: процесс pid = %i остановлен сигналом = %i\n", cpid, WSTOPSIG(status));
sleep(1);
printf(" РП: посылаю сигнал SIGCONT процессу pid = %i\n", cpid); kill(cpid, SIGCONT);
}
if (WIFEXITED(status)) {
printf(" РП: процесс pid = %i завершился со статусом = %i\n", cpid, WEXITSTATUS(status));
}
}
puts("Завершение проекта lab9.7 ..."); return EXIT_SUCCESS;
}
138 Пример запуска этой программы представлен на рисунке 3.7.
Рисунок 3.7 — Посылка сигналов дочерним процессам
В приложениях так же часто используются системные вызовы, останавливающие выполнение процесса. К ним относятся:
#include <unistd.h>
unsigned int sleep(unsigned int seconds); int pause(void);
где seconds — число секунд, на которое процесс «засыпает».
Эти вызовы не посылают родительскому процессу сигналов, но сами реагируют на сигнал SIGCONT. Поэтому, когда они блокируют выполнение программы, родительский процесс может снять их действие по тайм-ауту, посылая сигнал.
139 На листинге 3.8 представлена программа, в которой:
•родительский процесс, в цикле, создает пять дочерних процессов, после чего «засыпает» на 5 секунд, а затем посылает всем дочерним процессам сигнал
SIGCONT;
•все дочерние процессы регистрируют обработчик сигнала SIGCONT;
•первые два дочерних процесса останавливают свою работу с помощью системного вызова pause(...);
•остальные дочерние процессы останавливают свою работу с помощью системного вызова sleep(…).
Листринг 3.8 — Пример перезапуска дочерних процессов по тайм-ауту
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h>
int np = 0; |
|
// Номер дочернего процесса |
|
void handler(int sig){ |
// Обработчик сигнала |
|
|
printf(" |
ДП%i pid=%i: получил сигнал %i\n", np, getpid(), sig); |
|
|
} |
|
|
|
int main(void) { |
|
|
|
puts("Проект lab9.8 ..."); |
|
||
pid_t pid, cpid; |
|
|
|
int i, status=0xAAAA; |
|
||
puts("Запуск пяти дочерних процессов:"); |
|
||
for (i=0; i<5; i++) { |
|
||
pid = fork(); |
|
||
if (pid > 0) { |
|
||
|
printf(" |
Родителский процесс: Запустил ДП%i с pid = %i\n", |
i, pid); |
}else{ |
// Дочерние процессы |
|
|
|
np = i; |
|
|
|
signal(SIGCONT, handler); // Регистрирую обработчик сигнала SIGCONT |
||
if (i < 3){
printf(" |
ДП%i pid=%i: останавливаюсь pause()...\n", i, getpid()); |
|
pause(); |
|
|
}else{ |
|
|
printf(" |
ДП%i pid=%i: останавливаюсь sleep(100)\n", |
i, getpid()); |
sleep(100); |
|
|
} |
|
|
printf(" |
ДП%i pid=%i: Завершаюсь со статусом = %i\n", i, getpid(), i); |
|
exit(i); |
|
|
}
}
puts("Ожидание завершения дочерних процессов:"); sleep(5);
if (kill(0, SIGCONT) < 0){ // Посылаю сигнал всем, входящим в мою группу perror("kill():");
}
while((cpid = waitpid(-1, &status, WUNTRACED)) > 0) { if (WIFSTOPPED(status)) {
printf(" РП: процесс pid = %i остановлен сигналом = %i\n", cpid, WSTOPSIG(status));
sleep(1);
printf(" РП: посылаю сигнал SIGCONT процессу pid = %i\n", cpid); kill(cpid, SIGCONT);
}
140
if (WIFEXITED(status)) {
printf(" РП: процесс pid = %i завершился со статусом = %i\n", cpid, WEXITSTATUS(status));
}
}
puts("Завершение проекта lab9.8 ..."); return EXIT_SUCCESS;
}
На рисунке 3.8 показан результат работы этой программы.
Рисунок 3.8 — Пробуждение процессов обработчиком сигналов