C语言 我必须使用Posix定时器的信号处理程序吗?

i86rm4rw  于 2023-08-03  发布在  其他
关注(0)|答案(3)|浏览(120)

我想启动一个计时器,并在它到期时调用一个函数。
google找到了很多例子,包括手册中的例子,所有的例子都使用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()的 Package 器?为什么这些示例显式地设置信号处理程序?
另外,如果我通过这个方法或者通过timer_settime和一个信号处理程序启动一个计时器,取消计时器会导致系统删除该计时器和回调之间的关联吗?还是我必须显式地这样做?
[更新]您可以选择 * 信号或我在下面的答案中显示的方法(或两者都选,但这似乎很傻)。这是一个品味的问题。信号可能会提供更多的功能,但代价是复杂化。
如果你想做的只是启动一个计时器,并在计时器到期时得到通知,那么我的答案中的方法是最简单的。

d6kp6zgx

d6kp6zgx1#

Michael Kerrisk在他的《The Linux Programming Interface》一书中有一个详细的例子:

/* 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秒的间隔。
帮助器函数的定义可以通过本书上面的源代码链接找到。

kd3sttzy

kd3sttzy2#

看起来我不需要使用信号处理程序,可以使代码更简单,如下所示:

#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

6kkfgxo0

6kkfgxo03#

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

相关问题