下面这个例程使用2个参数,一个是睡眠周期,以秒为单位,另一个是时钟间隔,以纳秒为单位。程序执行如下指令:
假设在程序睡眠期间计时器至少到期一次,信号量处理函数 handler 将被调用并显示有关计时器通知的信息。程序在信号量处理函数被调用一次后退出。
以下程序在创建计时器后睡眠1秒钟,计时器周期为100纳秒当信号量被去阻塞并发出后,有约一千万(10,000,000)次超时。$ ./a.out 1 100 Establishing handler for signal 34 Blocking signal 34 timer ID is 0x804c008 Sleeping for 1 seconds Unblocking signal 34 Caught signal 34 sival_ptr = 0xbfb174f4; *sival_ptr = 0x804c008 overrun count = 10004886
#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <signal.h> #include <time.h> #define CLOCKID CLOCK_REALTIME #define SIG SIGRTMIN #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) static void print_siginfo(siginfo_t *si) { timer_t *tidp; int or; tidp = si->si_value.sival_ptr; printf(" sival_ptr = %p; ", si->si_value.sival_ptr); printf(" *sival_ptr = 0x%lx\n", (long) *tidp); or = timer_getoverrun(*tidp); if (or == -1) errExit("timer_getoverrun"); else printf(" overrun count = %d\n", or); } static void handler(int sig, siginfo_t *si, void *uc) { /* Note: calling printf() from a signal handler is not strictly correct, since printf() is not async-signal-safe; see signal(7) */ printf("Caught signal %d\n", sig); print_siginfo(si); signal(sig, SIG_IGN); } int main(int argc, char *argv[]) { timer_t timerid; struct sigevent sev; struct itimerspec its; long long freq_nanosecs; sigset_t mask; struct sigaction sa; if (argc != 3) { fprintf(stderr, "Usage: %s <sleep-secs> <freq-nanosecs>\n", argv[0]); exit(EXIT_FAILURE); } /* Establish handler for timer signal */ printf("Establishing handler for signal %d\n", SIG); sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = handler; sigemptyset(&sa.sa_mask); if (sigaction(SIG, &sa, NULL) == -1) errExit("sigaction"); /* Block timer signal temporarily */ printf("Blocking signal %d\n", SIG); sigemptyset(&mask); sigaddset(&mask, SIG); if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1) errExit("sigprocmask"); /* Create the timer */ sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIG; sev.sigev_value.sival_ptr = &timerid; if (timer_create(CLOCKID, &sev, &timerid) == -1) errExit("timer_create"); printf("timer ID is 0x%lx\n", (long) timerid); /* Start the timer */ freq_nanosecs = atoll(argv[2]); its.it_value.tv_sec = freq_nanosecs / 1000000000; its.it_value.tv_nsec = freq_nanosecs % 1000000000; its.it_interval.tv_sec = its.it_value.tv_sec; its.it_interval.tv_nsec = its.it_value.tv_nsec; if (timer_settime(timerid, 0, &its, NULL) == -1) errExit("timer_settime"); /* Sleep for a while; meanwhile, the timer may expire multiple times */ printf("Sleeping for %d seconds\n", atoi(argv[1])); sleep(atoi(argv[1])); /* Unlock the timer signal, so that timer notification can be delivered */ printf("Unblocking signal %d\n", SIG); if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) errExit("sigprocmask"); exit(EXIT_SUCCESS); }
found at http://www.kernel.org/doc/man-pages/.
Linux 2010-09-27 TIMER_CREATE(2)
以上 即 Linux man文档中的部分翻译,精力有限,不足以后增补。
由于上面的例程给出的是异步时钟,没有给出类似Win32中SetTimer 或 timeSetEvent 的计时器触发机制,网上找到sevp.sigev_notify 等于 SIGEV_THREAD时的例程,供学习参考。
/* * sigev_thread.c * * Demonstrate use of the SIGEV_THREAD signal mode to handle * signals by creating a new thread. * * Special notes: This program will not compile on Solaris 2.5. * It will compile on Digital UNIX 4.0 but will not work. * Digital UNIX 4.0c fixes SIGEV_THREAD, and sources inform me * that Solaris 2.6 will also fix SIGEV_THREAD. To try this on * Solaris 2.5, remove the "#ifdef sun" conditionals in main. */ #include <pthread.h> #include <sys/signal.h> #include <sys/time.h> #include "errors.h" timer_t timer_id; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int counter = 0; /* * Thread start routine to notify the application when the * timer expires. This routine is run "as if" it were a new * thread, each time the timer expires. * * When the timer has expired 5 times, the main thread will * be awakened, and will terminate the program. */ void timer_thread (void *arg) { int status; status = pthread_mutex_lock (&mutex); if (status != 0) err_abort (status, "Lock mutex"); if (++counter >= 5) { status = pthread_cond_signal (&cond); if (status != 0) err_abort (status, "Signal condition"); } status = pthread_mutex_unlock (&mutex); if (status != 0) err_abort (status, "Unlock mutex"); printf ("Timer %d\n", counter); } main() { int status; struct itimerspec ts; struct sigevent se; #ifdef sun fprintf ( stderr, "This program cannot compile on Solaris 2.5.\n" "To build and run on Solaris 2.6, remove the\n" "\"#ifdef sun\" block in main().\n"); #else /* * Set the sigevent structure to cause the signal to be * delivered by creating a new thread. */ se.sigev_notify = SIGEV_THREAD; se.sigev_value.sival_ptr = &timer_id; se.sigev_notify_function = timer_thread; se.sigev_notify_attributes = NULL; /* * Specify a repeating timer that fires each 5 seconds. */ ts.it_value.tv_sec = 5; ts.it_value.tv_nsec = 0; ts.it_interval.tv_sec = 5; ts.it_interval.tv_nsec = 0; DPRINTF (("Creating timer\n")); status = timer_create(CLOCK_REALTIME, &se, &timer_id); if (status == -1) errno_abort ("Create timer"); DPRINTF (( "Setting timer %d for 5-second expiration...\n", timer_id)); status = timer_settime(timer_id, 0, &ts, 0); if (status == -1) errno_abort ("Set timer"); status = pthread_mutex_lock (&mutex); if (status != 0) err_abort (status, "Lock mutex"); while (counter < 5) { status = pthread_cond_wait (&cond, &mutex); if (status != 0) err_abort (status, "Wait on condition"); } status = pthread_mutex_unlock (&mutex); if (status != 0) err_abort (status, "Unlock mutex"); #endif /* Sun */ return 0; }