我是否必须为Posix计时器使用信号处理程序?

时间:2016-07-13 10:11:25

标签: c timer posix sigaction

我想启动一个计时器,并在它到期时调用一个函数。

谷歌搜索发现了很多例子,包括手册中的例子,所有例子都使用sigaction()来设置信号处理程序。

然而,@ Patryk在this question中说我们可以

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

更短,更简单,更清洁,更易于维护......

是什么给出的?它是否正确?它只是sigaction()的包装器吗?为什么示例明确设置了信号处理程序?

此外,如果我通过此方法启动计时器,或通过timer_settime和信号处理程序启动计时器,将取消计时器casue系统以删除该计时器与回调之间的关联,或者我是否必须明确地这样做?

[更新]您可以选择 信号或我在下面的答案中显示的方法(或两者兼而有之,但这看起来很愚蠢)。这是一个品味问题。在以复杂为代价的情况下,Singals可能会提供更多的功能。

如果您只想启动计时器并在计时器到期时收到通知,那么我的答案中的方法最简单。

3 个答案:

答案 0 :(得分:2)

Linux有timerfd。 https://lwn.net/Articles/251413/。这将允许等待时间与select / poll / epoll一起使用。或者,您可以在select / poll / epoll上使用超时。

答案 1 :(得分:2)

Michael Kerrisk在他的" Linux编程接口"中有一个详细的例子。书:

/* ptmr_sigev_thread.c

   This program demonstrates the use of threads as the notification mechanism
   for expirations of a POSIX timer. Each of the program's command-line
   arguments specifies the initial value and interval for a POSIX timer. The
   format of these arguments is defined by the function itimerspecFromStr().

   The program creates and arms one timer for each command-line argument.
   The timer notification method is specified as SIGEV_THREAD, causing the
   timer notifications to be delivered via a thread that invokes threadFunc()
   as its start function. The threadFunc() function displays information
   about the timer expiration, increments a global counter of timer expirations,
   and signals a condition variable to indicate that the counter has changed.
   In the main thread, a loop waits on the condition variable, and each time
   the condition variable is signaled, the main thread prints the value of the
   global variable that counts timer expirations.

   Kernel support for Linux timers is provided since Linux 2.6. On older
   systems, an incomplete user-space implementation of POSIX timers
   was provided in glibc.
*/
#include <signal.h>
#include <time.h>
#include <pthread.h>
#include "curr_time.h"              /* Declares currTime() */
#include "tlpi_hdr.h"
#include "itimerspec_from_str.h"    /* Declares itimerspecFromStr() */

static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

static int expireCnt = 0;           /* Number of expirations of all timers */
static void                         /* Thread notification function */
threadFunc(union sigval sv)
{
    timer_t *tidptr;
    int s;

    tidptr = sv.sival_ptr;

    printf("[%s] Thread notify\n", currTime("%T"));
    printf("    timer ID=%ld\n", (long) *tidptr);
    printf("    timer_getoverrun()=%d\n", timer_getoverrun(*tidptr));

    /* Increment counter variable shared with main thread and signal
       condition variable to notify main thread of the change. */

    s = pthread_mutex_lock(&mtx);
    if (s != 0)
        errExitEN(s, "pthread_mutex_lock");

    expireCnt += 1 + timer_getoverrun(*tidptr);

    s = pthread_mutex_unlock(&mtx);
    if (s != 0)
        errExitEN(s, "pthread_mutex_unlock");

    s = pthread_cond_signal(&cond);
    if (s != 0)
        errExitEN(s, "pthread_cond_signal");
}
int
main(int argc, char *argv[])
{
    struct sigevent sev;
    struct itimerspec ts;
    timer_t *tidlist;
    int s, j;

    if (argc < 2)
        usageErr("%s secs[/nsecs][:int-secs[/int-nsecs]]...\n", argv[0]);

    tidlist = calloc(argc - 1, sizeof(timer_t));
    if (tidlist == NULL)
        errExit("malloc");

    sev.sigev_notify = SIGEV_THREAD;            /* Notify via thread */
    sev.sigev_notify_function = threadFunc;     /* Thread start function */
    sev.sigev_notify_attributes = NULL;
            /* Could be pointer to pthread_attr_t structure */

    /* Create and start one timer for each command-line argument */

    for (j = 0; j < argc - 1; j++) {
        itimerspecFromStr(argv[j + 1], &ts);

        sev.sigev_value.sival_ptr = &tidlist[j];
                /* Passed as argument to threadFunc() */

        if (timer_create(CLOCK_REALTIME, &sev, &tidlist[j]) == -1)
            errExit("timer_create");
        printf("Timer ID: %ld (%s)\n", (long) tidlist[j], argv[j + 1]);

        if (timer_settime(tidlist[j], 0, &ts, NULL) == -1)
            errExit("timer_settime");
    }

    /* The main thread waits on a condition variable that is signaled
       on each invocation of the thread notification function. We
       print a message so that the user can see that this occurred. */

    s = pthread_mutex_lock(&mtx);
    if (s != 0)
        errExitEN(s, "pthread_mutex_lock");

    for (;;) {
        s = pthread_cond_wait(&cond, &mtx);
        if (s != 0)
            errExitEN(s, "pthread_cond_wait");
        printf("main(): expireCnt = %d\n", expireCnt);
    }
}

取自online source code

另见本书第23章,这段代码在那里有详细解释。

要测试上面的代码,可以输入

$ ./ptmr_sigev_thread 5:5 10:10

这将设置两个定时器:一个初始有效期为5秒,间隔为5秒,另一个为10。

辅助函数的定义可以通过上面书籍源代码中的链接找到。

答案 2 :(得分:1)

似乎是,我不必使用信号处理程序,可以使代码更简单,如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>

static unsigned int pass_value_by_pointer = 42;

void Timer_has_expired(union sigval timer_data)
{
    printf("Timer expiration handler function; %d\n", *(int *) timer_data.sival_ptr);
}

int main(void)
{
    struct sigevent timer_signal_event;
    timer_t timer;

    struct itimerspec timer_period;

    printf("Create timer\n");
    timer_signal_event.sigev_notify = SIGEV_THREAD;
    timer_signal_event.sigev_notify_function = Timer_has_expired;       // This function will be called when timer expires
    // Note that the following is a union. Assign one or the other (preferably by pointer)
    //timer_signal_event.sigev_value.sival_int = 38;                        // This argument will be passed to the function
    timer_signal_event.sigev_value.sival_ptr = (void *) &pass_value_by_pointer;     // as will this (both in a structure)
    timer_signal_event.sigev_notify_attributes = NULL;
    timer_create(CLOCK_MONOTONIC, &timer_signal_event, &timer);

    printf("Start timer\n");
    timer_period.it_value.tv_sec = 1;                                   // 1 second timer
    timer_period.it_value.tv_nsec = 0;                                  // no nano-seconds
    timer_period.it_interval.tv_sec = 0;                                // non-repeating timer
    timer_period.it_interval.tv_nsec = 0;

    timer_settime(timer, 0, &timer_period, NULL);
    sleep(2);

    printf("----------------------------\n");
    printf("Start timer a second time\n");
    timer_settime(timer, 0, &timer_period, NULL);
    sleep(2);

    printf("----------------------------\n");
    printf("Start timer a third time\n");
    timer_settime(timer, 0, &timer_period, NULL);

    printf("Cancel timer\n");
    timer_delete(timer);
    sleep(2);
    printf("The timer expiration handler function should not have been called\n");

    return EXIT_SUCCESS;
}

运行时,它会输出:

Create timer
Start timer
Timer expiration handler function; 42
----------------------------
Start timer a second time
Timer expiration handler function; 42
----------------------------
Start timer a third time
Cancel timer
The timer expiration handler function should not have been called