POSIX 定时器在多次重复后失败

POSIX timer fail after many repeats

有人可以解释为什么计时器在 5-7 次迭代后因 SIGSEGV 而失败吗?

这两种情况都会发生:同步和不同步。 操作系统是 Ubuntu 15.04,Ubuntu GLIBC 2.21-0ubuntu4。

void timer_thread (sigval signal_value) {
    printf ("Timer callback!\n");
}

int main(int argc, char* argv[]) {

    const int TIMER_COUNT = 300;

    for (int i = 0; i < 10000; i++) {
        int status = 0;

        timer_t timer_id[TIMER_COUNT] = {};
        memset(&timer_id[0], 0, sizeof(timer_t)*TIMER_COUNT);

        for (int j = 0; j < TIMER_COUNT; j++) {

            struct itimerspec ts = {};
            struct sigevent se = {};

            memset(&ts, 0, sizeof(itimerspec));
            memset(&se, 0, sizeof(sigevent));

            se.sigev_notify = SIGEV_THREAD;
            se.sigev_value.sival_int = j;
            se.sigev_notify_function = timer_thread;

            // Specify a repeating timer that fires each 100000 nanosec.
            memset(&ts, 0, sizeof(ts));
            ts.it_value.tv_nsec = 100000;
            ts.it_interval.tv_nsec = 100000;

            status = timer_create(CLOCK_REALTIME, &se, &timer_id[j]);
            assert(!status && "Create timer");

            status = timer_settime(timer_id[j], 0, &ts, 0);
            assert(!status && "Set timer");
        }

        for (int j = 0; j < TIMER_COUNT; j++) {
            usleep(100);
            //stop and delete

            status = timer_delete(timer_id[j]);
            assert(!status && "Fail delete timer");
        }
    }
    printf("Success!\n");
    return 0;
}

GDB 回溯:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  __pthread_create_2_1 (newthread=newthread@entry=0x7f00e9817e28, attr=attr@entry=0x11c47e8, start_routine=start_routine@entry=0x7f00e93f6eb0 <timer_sigev_thread>, arg=<optimized out>)
    at pthread_create.c:711
711 pthread_create.c: No such file or directory.
(gdb) bt
#0  __pthread_create_2_1 (newthread=newthread@entry=0x7f00e9817e28, attr=attr@entry=0x11c47e8, start_routine=start_routine@entry=0x7f00e93f6eb0 <timer_sigev_thread>, arg=<optimized out>)
    at pthread_create.c:711
#1  0x00007f00e93f6e7a in timer_helper_thread (arg=<optimized out>) at ../sysdeps/unix/sysv/linux/timer_routines.c:125
#2  0x00007f00e91db6aa in start_thread (arg=0x7f00e9818740) at pthread_create.c:333
#3  0x00007f00e866feed in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109

构建命令行:/usr/bin/c++ -lrt -lpthread -g ./main.cc

Full code posix timer with synchronization

Full code posix timer with sleep

以下代码实际运行,不崩溃,编译干净

注意每个计时器的扩展时间间隔,这样大约 300 个计时器就有时间调用 printf() 和 return。

顺便说一句:在信号处理程序中调用 printf() 是一个非常糟糕的主意

#include <stdio.h>  // printf()
#include <stdlib.h> // exit(), EXIT_FAILURE
#include <signal.h>
#include <time.h>
#include <unistd.h> // sleep()
#include <string.h> // memset()

#define TIMER_COUNT (300)

#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                           } while (0)

void timer_thread (union sigval sigev_value)
{
    (void)sigev_value;
    static int count = 0;
    count++;
    fprintf ( stdout, "Timer callback count: %d\n", count);
}

int main( void )
{
    timer_t timer_id[TIMER_COUNT];
    memset(timer_id, '[=10=]', sizeof(timer_t)*TIMER_COUNT);

    struct itimerspec ts;
    struct sigevent se;

    for (size_t j = 0; j < TIMER_COUNT; j++)
    {
        memset(&ts, '[=10=]', sizeof(struct itimerspec));
        memset(&se, '[=10=]', sizeof(struct sigevent));

        se.sigev_notify = SIGEV_THREAD;
        se.sigev_value.sival_int = (int)j;
        se.sigev_notify_function = timer_thread;

        // Specify a repeating timer that fires each 2 second.
        ts.it_interval.tv_sec = 2;
        ts.it_interval.tv_nsec = 0;
        ts.it_value.tv_sec = ts.it_interval.tv_sec;
        ts.it_value.tv_nsec = ts.it_interval.tv_nsec;

        if( -1 == timer_create(CLOCK_REALTIME, &se, &timer_id[j]) )
            errExit( "timer_create failed" );

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

    sleep(10);

    for (int j = 0; j < TIMER_COUNT; j++)
    {
        //stop and delete
        fprintf( stdout, "stopping timer: %d, with ID:  %lu\n", j, (size_t)timer_id[j]);
        ts.it_value.tv_sec = 0;
        ts.it_value.tv_nsec = 0;
        ts.it_interval.tv_sec = 0;
        ts.it_interval.tv_nsec = 0;
        if( -1 == timer_settime( timer_id[j], 0, &ts, NULL) )
            errExit("timer_settime (to disable timer) failed" );

        fprintf( stdout, "deleting timer: %d, with ID:  %lu\n", j, (size_t)timer_id[j]);
        if( -1 == timer_delete(timer_id[j]) )
            errExit("timer_delete failed" );
    }

    printf("Success!\n");
    return 0;
} // end function: main