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
以下代码实际运行,不崩溃,编译干净
注意每个计时器的扩展时间间隔,这样大约 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
有人可以解释为什么计时器在 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
以下代码实际运行,不崩溃,编译干净
注意每个计时器的扩展时间间隔,这样大约 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