Несколько сигналов тревоги в C?

Вероятно, это очень простой вопрос, но я использую приведенный ниже код для запуска простого будильника. Он работает так, как я хочу, но мне интересно, возможно ли вообще запускать несколько будильников одновременно, чтобы каждый из них запускал другую функцию по завершении. Есть ли способ сделать это?

#include <signal.h>
#include <sys/time.h>
#include <stdio.h>
#include <time.h>

void alarm_handler(int signum){
    printf("five seconds passed!!\n");
}
int main(){
    signal(SIGALRM, alarm_handler);
    alarm(5);

    pause();
    return 0;
}

person Connor Olsen    schedule 22.05.2017    source источник
comment
Вы экспериментировали с ним?   -  person Richard    schedule 23.05.2017
comment
Часто можно использовать специфические функции ОС. В Linux вы найдете timerfd_create, а в BSD вы можете использовать любой открытый файловый дескриптор (т. е. тот, который открыт с помощью mkstemp), чтобы установить таймер, а затем опросить файловые дескрипторы... Имейте в виду, что таймеры являются ограниченным ресурсом ОС. Вы не всегда можете иметь их в наличии.   -  person Myst    schedule 23.05.2017
comment
Вы можете использовать timer_create (POSIX) вместо будильника, чтобы легко достичь своей цели.   -  person PSkocik    schedule 23.05.2017
comment
@PSkocik, мой опыт показывает, что timer_create не так портативна, как хотелось бы. Например, меня не существует в macOS. Хотя могу ошибаться (часто ошибаюсь).   -  person Myst    schedule 23.05.2017
comment
Будет ли это работать на ядре Linux?   -  person Connor Olsen    schedule 23.05.2017
comment
@ConnorOlsen В Linux 2.6 и новее должно быть.   -  person PSkocik    schedule 23.05.2017


Ответы (2)


Однако не с alarm(2) вы можете использовать таймеры POSIX для достижения своей цели.

Либо вы можете настроить каждый таймер на запуск другого сигнала по истечении его срока действия, либо вы можете использовать один сигнал и передать с ним указатель на таймер через siginfo_t, на основе которого вы затем можете решить, что делать в обработчике.

Пример:

#include <signal.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>

static timer_t tmid0, tmid1;

static void hndlr(int Sig, siginfo_t *Info, void *Ptr)
{
    if(Info->si_value.sival_ptr == &tmid0)
        write(2, "tmid0\n", 6);
    else{
        write(2, "tmid1\n", 6);
        _exit(0);
    }
}


int main()
{
    int r = EXIT_SUCCESS;

    sigaction(SIGALRM, &(struct sigaction){ .sa_sigaction = hndlr, .sa_flags=SA_SIGINFO }, 0);
    printf("%p %p\n", (void*)&tmid0, (void*)&tmid1);

    struct sigevent sev = { .sigev_notify = SIGEV_SIGNAL, .sigev_signo = SIGALRM };

    sev.sigev_value.sival_ptr = &tmid0; 
    if(0>timer_create(CLOCK_REALTIME,&sev,&tmid0))
        { r=EXIT_FAILURE; goto out; }

    sev.sigev_value.sival_ptr = &tmid1; 
    if(0>timer_create(CLOCK_REALTIME,&sev,&tmid1))
        { r=EXIT_FAILURE; goto out; }

    if(0>timer_settime(tmid0, 0, &(struct  itimerspec const){ .it_value={1,0} } , NULL) )
        { r=EXIT_FAILURE; goto out; }
     //tmid0 expires after 1 second

    if(0>timer_settime(tmid1, 0, &(struct  itimerspec const){ .it_value={3,0} } , NULL) )
        { r=EXIT_FAILURE; goto out; }
     //tmid1 expires after 3 seconds


    for(;;)
        pause();

out:
    if(r)
        perror(0); 
    return r;
}
person PSkocik    schedule 23.05.2017

Нет. Согласно этому источнику:

Запросы тревог не складываются; таким образом можно запланировать только одно поколение SIGALRM. Если сигнал SIGALRM еще не был сгенерирован, вызов должен привести к перепланированию времени, в которое сгенерирован сигнал SIGALRM.

Одним из вариантов является создание очереди с приоритетом, в которую вы ставите свои задачи, а затем всегда планируете свой будильник. для разницы во времени между текущим временем и задачей в верхней части очереди.

Но обязательно посмотрите на этот ТАК вопрос: вы re ограничен в том, что вы можете делать внутри вашего обработчика сигнала.

person Richard    schedule 22.05.2017