Проблема в таймерах и сигнале
Я реализовал таймер POSIX, используя API timer_create (), и он будет генерировать SIGUSR1, когда истечет таймер, для которого я поместил код обработчика. Теперь проблема в том, что если эта программа получает другой SIGUSR1, то тот же обработчик сигнала будет вызван и перехвачен.
Есть ли способ предотвратить это, чтобы обработчик мог перехватывать сигналы, генерируемые только таймером?
4 ответа
Будет ли это работать для вас? (Изменил код из примера в timer_create
справочная страница.)
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#define CLOCKID CLOCK_REALTIME
#define SIG SIGUSR1
timer_t timerid;
static void handler(int sig, siginfo_t *si, void *uc)
{
if(si->si_value.sival_ptr != &timerid){
printf("Stray signal\n");
} else {
printf("Caught signal %d from timer\n", sig);
}
}
int main(int argc, char *argv[])
{
struct sigevent sev;
struct itimerspec its;
long long freq_nanosecs;
sigset_t mask;
struct sigaction sa;
printf("Establishing handler for signal %d\n", SIG);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
sigaction(SIG, &sa, NULL);
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIG;
sev.sigev_value.sival_ptr = &timerid;
timer_create(CLOCKID, &sev, &timerid);
/* Start the timer */
its.it_value.tv_sec = 10;
its.it_value.tv_nsec = 0;
its.it_interval.tv_sec = its.it_value.tv_sec;
its.it_interval.tv_nsec = its.it_value.tv_nsec;
timer_settime(timerid, 0, &its, NULL);
sleep(100);
exit(EXIT_SUCCESS);
}
Когда сигнал от таймера пойман Caught signal 10 from timer
будет отображаться. Иначе Stray signal
будет отображаться.
Вопрос в том, действительно ли вам нужно использовать сигналы. Вы можете подумать об использовании обратного вызова, который будет вызываться по истечении таймера:
void cbf(union sigval);
struct sigevent sev;
timer_t timer;
sev.sigev_notify = SIGEV_THREAD;
sev.sigev_notify_function = cbf; //this function will be called when timer expires
sev.sigev_value.sival_ptr = (void*) arg;//this argument will be passed to cbf
timer_create(CLOCK_MONOTONIC, &sev, &timer);
Функция обратного вызова будет вызываться в новом потоке.
Используйте другие сигналы RT. См. Ответы на вопрос: есть ли способ создать пользовательский сигнал в Linux?
Нет, простого пути нет. Почему бы вам не использовать SIGUSR2 вместо своих таймеров, если у вас есть что-то еще, генерирующее SIGUSR1 вместе с вашим таймером. Если этого недостаточно, используйте один из сигналов реального времени для вашего приложения.
Если он должен иметь возможность обрабатывать один и тот же сигнал от таймера и какого-либо другого источника, то в зависимости от того, как быстро, сколько, какая система и т. Д. И т. Д. Вы можете попытаться установить временную метку перед регистрацией таймера, когда таймер приблизительно выйдет, а затем в обработчике сигнала попытайтесь определить, находится ли он в пределах временного интервала. Я бы настоятельно рекомендовал не использовать этот подход, а вместо этого переделать то, что вы делаете.