if (setprio(0, val) == -1) perror("set priority");
// периодически уведомлять родителя SIGUSR1, используя
// его как сигнал реального времени (с очередью):
while(true) {
sleep(del);
union sigval val;
val.sival_int = getprio(0);
// #define SIGUSR1 16
sigqueue(getppid, SIGUSR1, val);
}
}
Примечание
Для многих сигналов действием на их получение, предопределенным по умолчанию, является завершение процесса. (Реже встречается действие по умолчанию — игнорировать полученный сигнал при отсутствии явно установленной для него функции обработчика.) Достаточно странно, что завершение процесса предусмотрено как реакция по умолчанию на получение «пользовательских» сигналов SIGUSR1 и SIGUSR2. Если показанное выше приложение в процессе отладки запустить вызовом из командной строки (из командного интерпретатора или, например, файлового менеджера mqc), то результатом (на первый взгляд не столь ожидаемым) станет завершение интерпретатора командной строки (родительского процесса) и, как следствие, самого тестируемого приложения.
Вот как выглядит начальный участок совместной работы двух процессов:
# p1 15
parent main loop: priority = 10
SIG = 16: old priority = 10, new priority = 15
SIG = 16: old priority = 10, new priority = 15
parent main loop: priority = 10
SIG = 16: old priority = 10, new priority = 15
parent main loop: priority = 10
SIG = 16: old priority = 10, new priority = 15
parent main loop priority = 10
SIG = 16: old priority = 10, new priority = 15
parent main loop: priority = 10
SIG = 16: old priority = 10, new priority = 15
parent main loop: priority = 10
Отчетливо видно, что при посылке сигналов реального времени наследование приоритета посылающего процесса не происходит (дочернее приложение, посылающее сигнал, выполняется с приоритетом 15, а обработчик полученного сигнала в родительском процессе выполняется с приоритетом по умолчанию, равным 10).
Забегая вперед, сообщим, что в приведенном коде приложения сделано жалкое подобие имитации наследования приоритета: в качестве ассоциированного с сигналом реального времени значения передается значение приоритета отправителя, которое тут же устанавливается как приоритет для выполнения кода обработчика. Однако слабость в отношении истинного наследования состоит здесь в том, что два первых оператора (сохранение и установка приоритета) выполняются под приоритетом родителя, и в это время обработчик может быть вытеснен диспетчером системы.
Завершение процесса
С завершением процесса дело обстоит достаточно просто, по крайней мере, в сравнении с тем, что происходит при завершении потока, как это и будет показано очень скоро. Процесс завершается, если программа выполняет вызов
exit
или выполнение просто доходит до точки завершения функции
main
, будь то с явным указанием оператора
return
или без оного. Это естественный, внутренний (из программного кода самого процесса) путь завершения.