计时器和系统日志组合将导致我的代码挂起的情况

我尝试debugging由于在我的程序中使用计时器和系统日志function的问题。 在这里,我附上示例程序代码和terminal和系统日志的日志,以适当地进行debugging。

我不明白为什么这个程序会在一段时间后挂起。 所以在这里,我有2个问题,1.当定时器到期时,睡眠正在中断,因为它会产生SIGPROF 2.在一段时间或一段时间后,系统日志会被挂起

码:

#include <stdio.h> #include <time.h> #include <signal.h> #include <string.h> #include <unistd.h> #include <syslog.h> #define get_curr_date_time(date_time) \ { \ time_t t; \ time(&t); \ char *strtime = ctime(&t); \ strncpy(date_time, strtime, strlen(strtime) - 1); \ } #define DEBUG_INFO(p,x,arg...) \ {\ printf("%s:%d,1\n", __func__, __LINE__);\ char current_time[32] = {0}; \ printf("%s:%d,2\n", __func__, __LINE__);\ get_curr_date_time(current_time); \ printf("%s:%d,3\n", __func__, __LINE__);\ syslog(LOG_INFO,"[%s] : " p " : "#x"\n", current_time, ##arg);\ printf("%s:%d,4\n", __func__, __LINE__);\ } char exit_flag = 0; typedef struct _test_ctx_ { char timer_init; timer_t timerid; }test_ctx; void Timer_Handler(int sig, siginfo_t *si, void *uc) { printf("Timer handler is start\n"); DEBUG_INFO("timer_hang", "Timer handler is running\n"); printf("Timer handler is stop\n"); } int InitTimer(test_ctx *tst_ctx) { int status = 0; struct sigaction sa; struct sigevent sig; memset(&sig, 0x00, sizeof(struct sigevent)); memset(&sa, 0x00, sizeof(struct sigaction)); do { sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = Timer_Handler; sigemptyset(&sa.sa_mask); if (0 != (status = sigaction(SIGPROF, &sa, NULL))) { printf("Fail to register SIGPROF signal for timer, ret: %d\n", status); break; } sig.sigev_notify = SIGEV_SIGNAL; sig.sigev_signo = SIGPROF; sig.sigev_value.sival_ptr = &tst_ctx->timerid; if (0 != (status = timer_create(CLOCK_REALTIME, &sig, &(tst_ctx->timerid)))) { printf("Failed to create timer, ret: %d\n", status); break; } //Timer inited sucessfully tst_ctx->timer_init = 1; }while(0); return status; } void DeInitTimer(test_ctx *tst_ctx) { int status = 0; if (0 != tst_ctx->timer_init) { //Delete timer if (0 != (status = timer_delete(tst_ctx->timerid))) { printf("Fail to delete timer, ret: %d\n", status); } tst_ctx->timer_init = 0; } } int SetTimer(test_ctx *tst_ctx) { int status = 0; struct itimerspec in; memset(&in, 0x00, sizeof(struct itimerspec)); do { in.it_value.tv_sec = 0; in.it_value.tv_nsec = 1; in.it_interval.tv_sec = 0; in.it_interval.tv_nsec = 0; if (0 != (status = timer_settime(tst_ctx->timerid, 0, &in, NULL))) { printf("Fail to set timer, ret: %d\n", status); break; } }while(0); return status; } void terminate_app(int sig) { exit_flag = 1; printf("signal %d received exiting application\n", sig); DEBUG_INFO("timer_hang", "signal %d received exiting application\n", sig); } int main(int argc, char *argv[]) { int status = 0; test_ctx tst_ctx; memset(&tst_ctx, 0x00, sizeof(tst_ctx)); do { //Register signal handler signal(SIGTERM, terminate_app); signal(SIGINT, terminate_app); //Init timer status = InitTimer(&tst_ctx); if (0 != status) { break; } while(0 == exit_flag) { printf("Setting timer\n"); DEBUG_INFO("timer_hang", "Setting timer"); //Set Timer SetTimer(&tst_ctx); printf("Hello!!!\n"); DEBUG_INFO("timer_hang", "Hello!!!"); printf("Say!!!\n"); sleep(5); } }while(0); //De init timer DeInitTimer(&tst_ctx); return status; } 

结尾日志:

 root@AHMCPU0085:/home/ravi/work/test_app/timer_hang# ./hang_issue Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 main:154,4 Say!!! Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 main:154,4 Say!!! Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 main:154,4 Say!!! Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 main:154,4 Say!!! Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 main:154,4 Say!!! Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 main:154,4 Say!!! Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 main:154,4 Say!!! Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 main:154,4 Say!!! Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 main:154,4 Say!!! Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop Hello!!! main:154,1 main:154,2 main:154,3 main:154,4 Say!!! Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 main:154,4 Say!!! Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 main:154,4 Say!!! Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 main:154,3 Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop main:154,4 Say!!! Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 main:154,4 Say!!! Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 main:154,4 Say!!! Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 main:154,4 Say!!! Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 main:154,4 Say!!! Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 main:154,4 Say!!! Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 Timer_Handler:39,4 Timer handler is stop Setting timer main:148,1 main:148,2 main:148,3 main:148,4 Hello!!! main:154,1 main:154,2 main:154,3 Timer handler is start Timer_Handler:39,1 Timer_Handler:39,2 Timer_Handler:39,3 ^Csignal 2 received exiting application terminate_app:123,1 terminate_app:123,2 terminate_app:123,3 ^Z [1]+ Stopped ./hang_issue root@AHMCPU0085:/home/ravi/work/test_app/timer_hang# root@AHMCPU0085:/home/ravi/work/test_app/timer_hang# killall -s 9 hang_issue [1]+ Killed ./hang_issue root@AHMCPU0085:/home/ravi/work/test_app/timer_hang# root@AHMCPU0085:/home/ravi/work/test_app/timer_hang# 

Syslog消息:

 root@AHMCPU0085:/home/ravi/work/test_app/timer_hang# tail -f /var/log/messages ... Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Setting timer" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:15 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:15 2015] : timer_hang : "Hello!!!" Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Setting timer" Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Hello!!!" Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Setting timer" Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Hello!!!" Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Setting timer" Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:20 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:20 2015] : timer_hang : "Hello!!!" Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Setting timer" Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Hello!!!" Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Setting timer" Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Hello!!!" Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Setting timer" Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Hello!!!" Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Setting timer" Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Hello!!!" Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Setting timer" Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Hello!!!" Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Timer handler is running\n" Jan 21 10:52:25 AHMCPU0085 hang_issue: [Wed Jan 21 10:52:25 2015] : timer_hang : "Setting timer" ^C root@AHMCPU0085:/home/ravi/work/test_app/timer_hang# 

您将通过执行以下步骤在您的Linux机器上运行此testing应用程序:

 # gcc -o hang_issue timer_hang.c -Wall -lrt # ./hang_issue ... <You will get logs> ... 

任何帮助将不胜感激。

问候,拉维

如注释中所述,不能在信号处理程序中使用syslog() 。 它不是异步信号安全的 ,而且作为一个复杂的功能(根据需要打开和关闭与系统日志的连接),使用它也难怪奇怪和不同的方式导致程序失败。

而是使用write()和标准输出以及标准错误流。 例如,

 #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> static void wr(int fd, const void *const ptr, const size_t len) { const char *p = (const char *)ptr; const char *const q = (const char *)ptr + len; ssize_t n; while (p < q) { n = write(fd, p, (size_t)(q - p)); if (n > (ssize_t)0) p += n; else if (n != (ssize_t)-1 || errno != EINTR) return; } } static void wrerr(const char *const string) { if (string != NULL) wr(STDERR_FILENO, string, strlen(string)); } static void wrout(const char *const string) { if (string != NULL) wr(STDOUT_FILENO, string, strlen(string)); } 

在上面, wrout()wrerr()只接受一个字符串(比如puts() ,除了这些不会自动附加一个换行符),并不像printf()那样有用,但是它们是异步信号安全的,从信号处理程序中使用。

请记住,在使用Bash时,可以使用>out将标准输出重定向到文件out2>err将标准错误重定向到文件err 。 输出到终端出奇的慢,所以对于任何时间,重定向到文件(或更好的是,不要输出额外的调试信息)。

如果您确实需要将信号处理程序的某些输出发送到syslog,则需要使用管道对或套接字对,并从另一端读取线程或子进程,然后将数据发送到syslog。 然后,只需使用异步信号安全函数,从信号处理程序write()管道或套接字对(使用write() )即可。 (显然,读取和系统日志数据的线程或子进程不需要使用异步信号安全函数 – 毕竟,它不是一个信号处理程序。)


一般来说,我们来讨论超时的话题。

我建议不要使用超时的正常信号。 如果你需要信号,比如在特定的线程中中断一个阻塞的系统调用,可以使用一个实时信号( SIGRTMIN+0SIGRTMAX-0 )。

实际上,使用单独的线程来处理一组超时会更好。 下面是一个例子,使用少于400行的代码,它允许您使用任意数量的并发超时,并提供易失性标志和超时信号,以方便使用。 它使用CLOCK_MONOTONIC时钟,它不容易出现跳转(UTC秒,夏时制等),但是会保持实时时钟(挂钟)的滴答速率:

 #define _POSIX_C_SOURCE 200809L #include <stdlib.h> #include <string.h> #include <pthread.h> #include <semaphore.h> #include <time.h> #include <errno.h> #include <stdio.h> /* Number of timeouts to test. */ #ifndef TIMEOUT_TESTS #define TIMEOUT_TESTS 100000 #endif /* Seconds per timeout. */ #ifndef TIMEOUT_SECONDS #define TIMEOUT_SECONDS 0.000000001 #endif /* Timeout thread worker stack size; uses very few local variables. */ #define TIMEOUT_STACK_SIZE 65536 typedef struct timeout timeout; struct timeout { struct timeout *next; struct timespec abstime; /* Using CLOCK_MONOTONIC clock */ sem_t elapsed; /* sem_post()ed when elapsed */ volatile int pending; /* Cleared to zero when expires */ }; static volatile int timeouts_error = -1; static pthread_t timeouts_thread; static pthread_mutex_t timeout_lock; static pthread_cond_t timeout_cond; /* Uses CLOCK_MONOTONIC clock */ static timeout *volatile timeout_pending = NULL; static void *timeouts_worker(void *unused __attribute__((unused))) { struct timespec now; timeout *curr; int err; err = pthread_mutex_lock(&timeout_lock); if (err) { timeouts_error = err; pthread_cond_signal(&timeout_cond); return (void *)(long)err; } timeouts_error = 0; pthread_cond_signal(&timeout_cond); while (!timeouts_error) { /* If there are no pending timeouts, * all we need to do is wait for a condition. */ if (timeout_pending == NULL) { pthread_cond_wait(&timeout_cond, &timeout_lock); continue; } /* CLOCK_MONOTONIC is used for the timeouts. */ if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) { timeouts_error = errno; pthread_mutex_unlock(&timeout_lock); return (void *)(long)timeouts_error; } /* Trigger and remove all timeouts that have elapsed thus far. */ curr = timeout_pending; while (curr != NULL && (curr->abstime.tv_sec < now.tv_sec || (curr->abstime.tv_sec == now.tv_sec && curr->abstime.tv_nsec <= now.tv_nsec))) { timeout *const prev = curr; curr = prev->next; prev->next = NULL; /* Mark 'prev' timeout elapsed. */ prev->pending = 0; sem_post(&(prev->elapsed)); } /* No more timeouts? */ if (timeout_pending == NULL) continue; /* Wait for the next one to elapse. * TODO: Adjust 'now' according to previous over/undershoots, * Say, by one tenth of previous wakeup error * (ie dynamically estimating the _timedwait latency). * This would result in much more accurate timeouts. */ now = timeout_pending->abstime; pthread_cond_timedwait(&timeout_cond, &timeout_lock, &now); } return (void *)0L; } static int timeout_free(timeout *const old_timeout) { int err; if (old_timeout == NULL) return 0; err = pthread_mutex_lock(&timeout_lock); if (err) return errno = err; /* We also leak memory here. */ /* Remove from timeout_pending chain. */ if (timeout_pending == old_timeout) timeout_pending = old_timeout->next; else { timeout *temp = timeout_pending; if (temp != NULL) while (temp->next != NULL) if (temp->next == old_timeout) { temp->next = old_timeout->next; break; } else temp = temp->next; } /* Unlock mutex; we no longer need to access the chain. */ pthread_mutex_unlock(&timeout_lock); /* Poison and free the timeout structure. */ sem_destroy(&(old_timeout->elapsed)); old_timeout->next = NULL; old_timeout->abstime.tv_sec = 0; old_timeout->abstime.tv_nsec = 0; old_timeout->pending = 0; free(old_timeout); return 0; } static timeout *timeout_after(const double seconds) { const long sec = (long)seconds; const long nsec = (long)(1000000000.0 * (seconds - (double)sec)); struct timespec now; timeout *new_timeout; int err; /* Negative time is not allowed. */ if (seconds < 0.0) { errno = EINVAL; return NULL; } /* Get current monotonic time. */ if (clock_gettime(CLOCK_MONOTONIC, &now)) return NULL; new_timeout = malloc(sizeof *new_timeout); if (new_timeout == NULL) { errno = ENOMEM; return NULL; } if (sem_init(&(new_timeout->elapsed), 0, 0) == -1) { err = errno; free(new_timeout); errno = err; return NULL; } new_timeout->next = NULL; new_timeout->abstime.tv_sec = now.tv_sec + sec + (now.tv_nsec + nsec) / 1000000000L; new_timeout->abstime.tv_nsec = (now.tv_nsec + nsec) % 1000000000L; new_timeout->pending = 1; /* Already elapsed? */ if (new_timeout->abstime.tv_sec < now.tv_sec || (new_timeout->abstime.tv_sec == now.tv_sec && new_timeout->abstime.tv_nsec <= now.tv_nsec)) { new_timeout->next = NULL; new_timeout->pending = 0; sem_post(&(new_timeout->elapsed)); return new_timeout; } /* Get timeout lock, to add to chain. */ err = pthread_mutex_lock(&timeout_lock); if (err) { sem_destroy(&(new_timeout->elapsed)); free(new_timeout); errno = err; return NULL; } if (timeout_pending == NULL) timeout_pending = new_timeout; else if (timeout_pending->abstime.tv_sec > new_timeout->abstime.tv_sec || (timeout_pending->abstime.tv_sec == new_timeout->abstime.tv_sec && timeout_pending->abstime.tv_nsec >= new_timeout->abstime.tv_nsec)) { new_timeout->next = timeout_pending; timeout_pending = new_timeout; } else { timeout *temp = timeout_pending; while (temp->next != NULL && (temp->next->abstime.tv_sec > new_timeout->abstime.tv_sec || (temp->next->abstime.tv_sec == new_timeout->abstime.tv_sec && temp->next->abstime.tv_nsec >= new_timeout->abstime.tv_nsec))) temp = temp->next; new_timeout->next = temp->next; temp->next = new_timeout; } /* Timeout chain manipulated; notify and unlock. */ pthread_cond_signal(&timeout_cond); pthread_mutex_unlock(&timeout_lock); errno = 0; return new_timeout; } static int timeouts_end(void) { if (timeouts_error == 0) { int err; void *errptr; pthread_mutex_lock(&timeout_lock); timeouts_error = -1; pthread_cond_signal(&timeout_cond); pthread_mutex_unlock(&timeout_lock); err = pthread_join(timeouts_thread, &errptr); if (err == 0) err = (long)errptr; return errno = err; } else if (timeouts_error != -1) { int err; void *errptr; err = pthread_join(timeouts_thread, &errptr); if (err == 0) err = (long)errptr; else err = timeouts_error; return errno = err; } else return errno = ENOENT; } static int timeouts_init(void) { pthread_mutexattr_t lock_attrs; pthread_condattr_t cond_attrs; pthread_attr_t attrs; void *errptr; int err; if (timeouts_error != -1) return errno = EEXIST; /* Initialize timeout_lock as an adaptive mutex. */ err = pthread_mutexattr_init(&lock_attrs); if (err) return errno = err; err = pthread_mutexattr_settype(&lock_attrs, PTHREAD_MUTEX_ADAPTIVE_NP); if (err) return errno = err; err = pthread_mutex_init(&timeout_lock, &lock_attrs); if (err) return errno = err; err = pthread_mutexattr_destroy(&lock_attrs); if (err) return errno = err; /* Initialize timeout_cond as a process-private monotonic clock condition variable. */ err = pthread_condattr_init(&cond_attrs); if (err) return errno = err; err = pthread_condattr_setpshared(&cond_attrs, PTHREAD_PROCESS_PRIVATE); if (err) return errno = err; err = pthread_condattr_setclock(&cond_attrs, CLOCK_MONOTONIC); if (err) return errno = err; err = pthread_cond_init(&timeout_cond, &cond_attrs); if (err) return errno = err; err = pthread_condattr_destroy(&cond_attrs); if (err) return errno = err; /* Initialize the thread attributes to a 64k stack. */ err = pthread_attr_init(&attrs); if (err) return errno = err; err = pthread_attr_setstacksize(&attrs, TIMEOUT_STACK_SIZE); if (err) return errno = err; /* Grab the timeout lock; we'll wait on the cond later. */ err = pthread_mutex_lock(&timeout_lock); if (err) return errno = err; /* Start the timeout worker thread. */ err = pthread_create(&timeouts_thread, &attrs, timeouts_worker, NULL); if (err) return errno = err; pthread_attr_destroy(&attrs); /* Wait for the worker to be ready. */ pthread_cond_wait(&timeout_cond, &timeout_lock); /* Failed? */ if (timeouts_error != 0) { timeouts_error = -1; pthread_mutex_unlock(&timeout_lock); err = pthread_join(timeouts_thread, &errptr); if (err == 0) err = (long)errptr; return errno = err; } /* Unlock. */ pthread_mutex_unlock(&timeout_lock); /* Success. */ return 0; } int main(void) { long i; timeout *t; if (timeouts_init()) { fprintf(stderr, "Cannot initialize timeouts: %s.\n", strerror(errno)); return EXIT_FAILURE; } fprintf(stderr, "Testing:\n"); fflush(stderr); for (i = 1L; i <= TIMEOUT_TESTS; i++) { t = timeout_after(0.000000001); if (t == NULL) { fprintf(stderr, "Test %ld of %ld failed: Cannot obtain a timeout: %s.\n", i, (long)TIMEOUT_TESTS, strerror(errno)); timeouts_end(); return EXIT_FAILURE; } printf("Timeout %ld of %ld: ", i, (long)TIMEOUT_TESTS); fflush(stdout); /* Wait for timeout to elapse. */ sem_wait(&(t->elapsed)); printf("Elapsed.\n"); fflush(stdout); timeout_free(t); } if (timeouts_end()) { fprintf(stderr, "Error in disarming timeouts: %s.\n", strerror(errno)); return EXIT_FAILURE; } fprintf(stderr, "No errors.\n"); return EXIT_SUCCESS; } 

由于我们有一个专用的超时工作者线程,因此上面使用pthread_cond_timedwait()等待下一个超时发生(条件变量设置为使用CLOCK_MONOTONIC时钟源)或信号(由另一个线程插入新的超时)。

要中断阻塞系统调用,请将pthread_t thread添加到timeout结构中,使timeout_after()将其设置为pthread_self() 。 安装一个实时信号(例如SIGRTMIN+0 )处理程序(具有空的主体 – 交付是重要的,而不是处理程序的功能)。 最后,在timeouts_worker()添加pthread_kill(curr->thread, SIGRTMIN+0)以在目标线程中引发信号。

上面的实现使用了一个简单的排序链接列表timeout_pending来保持当前等待的超时。 这会在添加,删除和触发超时时产生O(N)行为,如果您有数百或数千个并发超时,那么这是非常不理想的。 用二进制最小堆替换列表处理,以获得更好的性能,并发超时。

另外,没有必要总是向超时工作者发出新的超时信号。 由于加法器持有互斥量,只有当新的超时被添加为下一个时间时才会发出信号。

代码编译,但我没有彻底检查逻辑,所以可能有一些潜伏的错误。 如果你找到了,让我知道,我会尽量修复它们。 (尽管我很确定算法和方法本身是有效的。)

我不认为上面的代码版权,因为它是如此简单,但如果有人这样做,我认为它是在公共领域,并在那些不具有法律概念,根据知识共享零许可授权的司法辖区。 简而言之:做你想做的事,但没有保证,你不能责怪我的任何破坏。

有问题吗? 注释? Bug修复?