Linux 定时器和信号问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5740954/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 03:45:59  来源:igfitidea点击:

Problem in Timers and signal

clinuxtimersignals

提问by kingsmasher1

I have implemented a POSIX timer using timer_create( ) API, and this will generate SIGUSR1 when the timer expires for which i have put a handler code. Now the problem is, if this program receives another SIGUSR1, then the same signal handler will be invoked and caught.

我已经使用 timer_create() API 实现了一个 POSIX 计时器,这将在计时器到期时生成 SIGUSR1,我已经为其放置了处理程序代码。现在的问题是,如果这个程序接收到另一个 SIGUSR1,那么将调用并捕获相同的信号处理程序。

Is there any way to prevent this, so that the handler can catch signals only generated by the timer?

有什么方法可以防止这种情况发生,以便处理程序可以捕获仅由计时器生成的信号?

采纳答案by Rumple Stiltskin

Will this work for you? (Modified the code from example in timer_createman page.)

这对你有用吗?(修改了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);
}

When signal from timer is caught Caught signal 10 from timerwill be displayed. Otherwise Stray signalwill be displayed.

当来自定时器的信号被捕获时Caught signal 10 from timer将显示。否则Stray signal会显示。

回答by Patryk

The question is whether you really need to use signals. You may think of using callback that will be called when the timer expires:

问题是你是否真的需要使用信号。您可能会想到使用将在计时器到期时调用的回调:

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);

The callback function will be called in a new thread.

回调函数将在新线程中调用。

回答by Milan

No, there is no easy way. Why don't you use SIGUSR2 instead for your timers if you have something else generating SIGUSR1 together with your timer. If that is not enough, use one of the real time signals for your application.

不,没有简单的方法。如果您有其他东西与您的计时器一起生成 SIGUSR1,为什么不使用 SIGUSR2 代替您的计时器。如果这还不够,请为您的应用程序使用一种实时信号。

If it must be able to handle the same signal from the timer and some other source, then depending on how fast, how many, what system, etc etc you could try setting a timestamp before registering a timer on when the timer will approximately exit, and then in the signal handler try to deduce if it was within time margin. I would strongly advise not to use this approach, but instead redesign what you are doing.

如果它必须能够处理来自计时器和其他一些来源的相同信号,那么根据多快、多少、什么系统等,您可以尝试在注册计时器之前设置时间戳,以确定计时器大约何时退出,然后在信号处理程序中尝试推断它是否在时间裕度内。我强烈建议不要使用这种方法,而是重新设计你正在做的事情。

回答by Yann Droneaud