POSIX определяет функцию именно для вашей цели: sigtimedwait()
. Он будет приостанавливать выполнение вызывающего процесса до тех пор, пока или один из сигналов в указанном наборе не станет ожидающим, или истечет указанное время ожидания. Его возвращаемое значение указывает, какие из них произошли.
В течение этого периода, если первый процесс предоставляет данные и отправляет сигнал второму, все в порядке. В противном случае, если он не получит никакого сигнала от первого в течение этого периода, он будет делать другое.
Как я могу заставить второй процесс ответить на эту потребность?
Второй процесс устанавливает аргументы для sigtimedwait
. Затем он блокирует ожидаемый сигнал (через sigprocmask
), так что расположение по умолчанию не происходит при получении этого сигнала, а затем вызывает sigtimedwait
. Возвращаемое значение последнего указывает, был ли получен один из указанных сигналов (и если да, то какой), или же функция вернулась по какой-то другой причине - обычно из-за истечения времени ожидания. В последнем случае можно проверить переменную errno
, чтобы определить, действительно ли это был тайм-аут. На странице руководства, ссылка на которую приведена выше, содержатся некоторые дополнительные примечания по использованию.
В частности, вам нужно два основных аргумента:
a sigset_t
, определяющих сигналы для блокировки и ожидания после , В разделе «См. Также» в конце страницы руководства приведена документация по связанным и аналогичным функциям, включая sigsetops(3)
, в которой рассказывается о том, как управлять такими объектами. Например,
#include <signal.h>
// ...
sigset_t sigs;
sigemptyset(&sigs);
sigaddset(&sigs, SIGUSER2);
a struct timespec
, чье определение приведено на странице руководства. Это определение должно быть достаточным для того, чтобы вы получили что-то вроде
struct timespec timeout = { .tv_sec = 10 };
Для документов вы можете указать второй аргумент sigtimedwait
как NULL
, если вы этого не сделаете Вам нужна информация, которая в противном случае могла бы быть передана вам тем или иным способом, а вы - нет.
Вы можете использовать уже подготовленный набор сигналов, как описано выше, для настройки блокировки сигналов, например:
sigprocmask(SIG_BLOCK, &sigs, NULL);
Это может показаться немного нелогичным, поскольку вы действительно хотите получить сигнал, но эффект состоит в том, чтобы заблокировать любое расположение, установленное для возникновения сигнала, что отличается от пути обработки его через sigtimedwait
.
На этом этапе вы готовы сделать вызов sigtimedwait()
:
int sig_num = sigtimedwait(&sigs, NULL, &timeout);
Результатом будет номер сигнала, если один из указанных сигналов (только SIGUSER2
в этом примере) принимается в течение указанного времени или -1 в противном случае. Следовательно,
if (sig_num == SIGUSER2) {
// I received the signal
// do something ...
} else {
// assert(sig_num == -1);
// I did not receive the signal within the alotted time
// do something else ...
}
Вы можете предположить, что тайм-аут произошел в случае, когда сигнал не получен, но наиболее надежный код проверяет errno
, чтобы убедиться, что:
if (errno == EAGAIN) {
// it was a timeout
} else if (errno = EINTR) {
// a signal outside the set was received
// ... might want to calculate how much wait time is left and try again
// (left as an exercise)
} else {
// some other error occurred
// ... aborting with an error might be best:
perror("signal wait failed unexpectedly");
exit(1);
}