使用timer_create在单独的pthread中的信号处理程序

时间:2015-08-29 05:59:06

标签: c timer

我正在开发一个小应用程序,我希望每隔1秒调用一个函数。这就是我实施的方式

Timerspec.it_interval.tv_sec=1;
Timerspec.it_interval.tv_nsec=0;
Timerspec.it_value.tv_sec=1;
Timerspec.it_value.tv_nsec=0;

timer_t timerId;

struct sigaction sa;
sa.sa_handler=&TimerFn;
sa.sa_flags=0;
sigemptyset(&sa.sa_mask);
sigaction(SIGALRM,&sa,NULL);

timer_create(CLOCK_REALTIME,NULL,&timerId);
timer_settime(timerId,0,(const itimerspec*)Timerspec,NULL);

但我想在单独的pthread中运行 TimerFn 函数(基本上是pthread函数的计时器)。有人可以告诉你怎么做吗?

2 个答案:

答案 0 :(得分:1)

如果您可以接受为每个计时器刻度创建新线程,则可以使用SIGEV_THREAD

struct sigevent evp;
memset((void *)&evp, 0, sizeof(evp));
evp.sigev_notify = SIGEV_THREAD;
evp.sigev_notify_function = &sig_alrm_handler;
evp.sigev_signo = SIGALRM;
evp.sigev_value.sigval_ptr = (void *)this;
int ret = timer_create(CLOCK_REALTIME, &evp, &_timerId);

这将为每个tick创建一个新线程。

如果您需要在特定线程中处理信号,则需要做更多工作:

static void *
sig_threadproc(void *thrarg)
{
    sigset_t sigset;
    sigemptyset(&sigset);
    sigaddset(&sigset, SIGALRM);

    /* endless loop to wait for and handle a signal repeatedly */
    for (;;) {
        int sig;
        int error;

        error = sigwait(&sigset, &sig);
        if (error == 0) {
            assert(sig == SIGALRM);
            printf("got SIGALRM\n");
        } else {
            perror("sigwait");
        }
    }
    return NULL;
}

static void
sig_alrm_handler(int signo)
{
    /**
     * dummy signal handler, 
     * the signal is actually handled in sig_threadproc() 
     **/
}


int
main(int argc, char *argv[])
{
    sigset_t sigset;
    struct sigaction sa;
    pthread_t sig_thread;
    struct itimerspec tspec;
    timer_t timer_id;

    /* mask SIGALRM in all threads by default */
    sigemptyset(&sigset);
    sigaddset(&sigset, SIGALRM);           
    sigprocmask(SIG_BLOCK, &sigset, NULL);

    /* we need a signal handler.
     * The default is to call abort() and 
     * setting SIG_IGN might cause the signal
     * to not be delivered at all.
     **/
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = sig_alrm_handler;
    sigaction(SIGALRM, &sa, NULL);

    /* create SIGALRM looper thread */
    pthread_create(&sig_thread, NULL, sig_threadproc, NULL);

    /* setup timer */
    tspec.it_interval.tv_sec = 1;
    tspec.it_interval.tv_nsec = 0;
    tspec.it_value.tv_sec = 1;
    tspec.it_value.tv_nsec = 0;

    timer_create(CLOCK_REALTIME, NULL, &timer_id);
    timer_settime(timer_id, 0, &tspec, NULL);

    /**
     * this might return early if usleep() is interrupted (by a signal)
     * It should not happen, since SIGALRM is blocked on the
     * main thread
     **/
    usleep(10000000);

    return 0;
}

您可能只在信号处理程序线程中选择性地解除阻塞SIGARLM,导致它唯一的线程有资格处理该信号,但可能无法跨系统移植。

其他版本(包括pthread_cond_signal()的使用)已在this answer中讨论过。

答案 1 :(得分:0)

如果您只是想每秒调用一个函数,这是一个简单的解决方案:

#include <pthread.h>
#include <unistd.h>
void TimerFn(void)
{
  ...
}
void* timer(void* arg)
{
  for (;;) {
    TimerFn();
    sleep(1);
  }
  return NULL;
}
...
  pthread_t timerThread;
  pthread_create(&timerThread, NULL, timer, NULL);

有什么理由这还不够吗?