Установите обработчик сигнала и вызовите доставку сигнала (используя alarm()
, setitimer()
или timer_create()
+timer_settime()
), чтобы доставка сигнала прервала вызов sem_wait()
.
Рассмотрим этот пример программы:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <semaphore.h>
#include <stdio.h>
#include <errno.h>
static void dummy_handler(int signum)
{
}
static int install_dummy_handler(int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = dummy_handler;
act.sa_flags = 0;
return sigaction(signum, &act, NULL);
}
static const char *errname(const int errnum)
{
switch (errnum) {
case EINTR: return "EINTR";
case EINVAL: return "EINVAL";
default: return "(other)";
}
}
int main(void)
{
sem_t s;
if (install_dummy_handler(SIGALRM) == -1) {
fprintf(stderr, "Cannot install ARLM signal handler: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
sem_init(&s, 0, 0);
alarm(1);
if (sem_wait(&s) == -1) {
const int errnum = errno;
printf("sem_wait() failed with errno == %s (%d; %s).\n",
errname(errnum), errnum, strerror(errnum));
} else
printf("sem_wait() succeeded.\n");
return EXIT_SUCCESS;
}
В main()
мы устанавливаем обработчик сигнала SIGALRM. Неважно, делает ли вообще что-либо функция обработчика сигнала, потому что именно доставка сигнала приводит к тому, что "медленные" системные вызовы возвращаются с ошибкой EINTR. (Поскольку флаг SA_RESTART не использовался при установке этого обработчика. Если вы посмотрите на act.sa_mask
в install_dummy_handler()
, вы увидите, что мы вообще не использовали флаги. Все флаги и sigaction()
использование описаны на справочной странице man 2 sigaction
.)
В main()
мы сначала инициализируем наш семафор, затем устанавливаем будильник на одну секунду. По истечении реального времени настенных часов поднимается сигнал SIGALRM. Обратите внимание, что хотя SIGALRM отлично подходит для этого примера и подобных целей, вы, вероятно, захотите использовать таймеры POSIX для каждого процесса вместо этого.
Затем мы просто вызываем sem_wait()
на семафоре и проверяем результат. На практике, если вы скомпилируете и запустите приведенный выше example.c, используя, например,
gcc -Wall -O2 example.c -lpthread -o example
./example
программа будет выводить
sem_wait() failed with errno == EINTR (4; Interrupted system call).
через одну секунду.
07.08.2018
sem_wait()
, и что именно доставка сигнала функции обработчика пользовательского пространства, а не сам сигнал, вызывает прерывание блокирующий вызов. В некоторых случаях вам может понадобиться пара сигналов, при этом первичный сигнал заблокирован во всех потоках, кроме одного, чтобы его обработчик сигналов мог пересылать сигнал (используя незаблокированный вторичный сигнал) каждому существующему другому потоку, чтобы прервать несколько потоков. . Дайте мне знать, если вам нужна дополнительная информация или пример. 08.08.2018