一、介紹
setitimer()創建一個間隔式定時器(interval timer),會在未來某個點到期,並於此後每隔一段時間到期一次
getitimer()獲取定時器瞭解當前狀態、距離下次到期的剩餘時間
alarm()爲創建一次性實時定時器提供簡單的一個接口
二、接口函數
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
參數:
seconds: 表示定時器到期的秒數,到期時會產生SIGALRM信號併發送給進程,因爲是實時和setitimer中的ITIMER_REAL一樣
注意: alarm 和 settimer都是針對同一進程的共享實時定時器,也就是兩者改變都會影響對方
調用alarm()會覆蓋定時器前一個設置,調用alarm(0)會屏蔽現有定時器
alarm()返回值是定時器前一個設置距離到期的剩餘次數,如未設置定時器則返回0
返回值:
alarm()返回的是剩餘定時器時間
#include <sys/time.h>
int setitimer(int which, const struct itimerval *new_value,
struct itimerval *old_value);
參數:
which: 指定不同類型的定時器
ITIMER_REAL: 創建以真實時間倒計時的定時器,到期時會產生SIGALRM信號併發送給進程
ITIMER_VIRTUAL:創建以進程虛擬時間(用戶態CPU時間)倒計時定時器,到期產生信號SIGVTALRM
ITIMER_PROF:創建一個運行時計時定時器,以進程時間(用戶態+內核CPU時間的總和)倒計時,到期產生信號SIGPROF
new_value:
參數new_value下的it_value指定了距離定時器到期的延遲時間,it_interval則說明該定時器是否爲週期性定時器,
如果it_interval兩個字段均爲0,那麼定時器就屬於在it_value所指定的時間間隔後到期的一次性定時器,
只要it_interval中的任一字段非0,那麼每次定時器到期後,都會將定時器重置爲指定間隔後再次到期。
注意:進程只能擁有which指定的三種中的一種,所以如果第二次調用setitimer修改類型要符合which中的類型,如果將
new_value->it_value下的兩個字段都設置0,會屏蔽任何已有的定時器。
old_value:
若不爲NULL,返回定時器前一設置。如果old_value->it_value兩個字段都爲0,那麼該定時器之前處於屏蔽狀態。
如果 old_valuee->it_interval兩個字段爲0,那麼前一次是一次性定時器,如果不關心前一次設置那麼設置NULL
返回值:
正確返回0,錯誤-1並設置errno
int getitimer(int which, struct itimerval *curr_value);
參數:
which: 參考setitimer
curr_value: 得到which指定類型的定時器信息
返回值:
正確返回0,錯誤-1並設置errno
SUSv4廢止了UNIX API setitimer&getitimer,推薦使用POSIX定時器API
struct itimerval {
struct timeval it_interval; /* Interval for periodic timer */
struct timeval it_value; /* Time until next expiration */
};
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
三、實例 setitimer
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <utime.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <dirent.h>
#include <limits.h>
#include <malloc.h>
#include <signal.h>
#include <setjmp.h>
#include <stdarg.h>
#ifdef TRUE
#undef TRUE
#endif
#define TRUE 1
#ifdef FALSE
#undef FALSE
#endif
#define FALSE 0
static volatile sig_atomic_t gotAlarm = 0;
void errExit(char * msg)
{
printf("%s\n",msg);
exit(EXIT_FAILURE);
}
void usageErr(const char *format, ...)
{
va_list argList;
fflush(stdout); /* Flush any pending stdout */
fprintf(stderr, "Usage: ");
va_start(argList, format);
vfprintf(stderr, format, argList);
va_end(argList);
fflush(stderr); /* In case stderr is not line-buffered */
exit(EXIT_FAILURE);
}
static void displayTimes(const char *msg, int includeTimer)
{
struct itimerval itv;
static struct timeval start;
struct timeval curr;
static int callNum = 0; /* Number of calls to this function */
if (callNum == 0) /* Initialize elapsed time meter */
if (gettimeofday(&start, NULL) == -1)
errExit("gettimeofday");
if (callNum % 20 == 0) /* Print header every 20 lines */
printf(" Elapsed Value Interval\n");
if (gettimeofday(&curr, NULL) == -1)
errExit("gettimeofday");
printf("%-7s %6.2f", msg, curr.tv_sec - start.tv_sec +(curr.tv_usec - start.tv_usec) / 1000000.0);
if (includeTimer) {
if (getitimer(ITIMER_REAL, &itv) == -1)
errExit("getitimer");
printf(" %6.2f %6.2f",itv.it_value.tv_sec + itv.it_value.tv_usec / 1000000.0,
itv.it_interval.tv_sec + itv.it_interval.tv_usec / 1000000.0);
}
printf("\n");
callNum++;
}
static void sigalrmHandler(int sig)
{
gotAlarm = 1;
}
int main(int argc, char *argv[])
{
struct itimerval itv;
clock_t prevClock;
int maxSigs; /* Number of signals to catch before exiting */
int sigCnt; /* Number of signals so far caught */
struct sigaction sa;
char *endptr;
if (argc > 1 && strcmp(argv[1], "--help") == 0)
usageErr("%s [secs [usecs [int-secs [int-usecs]]]]\n", argv[0]);
sigCnt = 0;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = sigalrmHandler;
if (sigaction(SIGALRM, &sa, NULL) == -1)
errExit("sigaction");
/* Set timer from the command-line arguments */
itv.it_value.tv_sec = (argc > 1) ? strtol(argv[1], &endptr, 10):0;
itv.it_value.tv_usec = (argc > 2) ? strtol(argv[1], &endptr, 10):2;
itv.it_interval.tv_sec = (argc > 3) ? strtol(argv[1], &endptr, 10):0;
itv.it_interval.tv_usec = (argc > 4) ? strtol(argv[1], &endptr, 10):0;
/* Exit after 3 signals, or on first signal if interval is 0 */
maxSigs = (itv.it_interval.tv_sec == 0 && itv.it_interval.tv_usec == 0) ? 1 : 3;
displayTimes("START:", FALSE);
if (setitimer(ITIMER_REAL, &itv, NULL) == -1)
errExit("setitimer");
prevClock = clock();
sigCnt = 0;
for (;;) {
/* Inner loop consumes at least 0.5 seconds CPU time */
while (((clock() - prevClock) * 10 / CLOCKS_PER_SEC) < 5) {
if (gotAlarm) { /* Did we get a signal? */
gotAlarm = 0;
displayTimes("ALARM:", TRUE);
sigCnt++;
if (sigCnt >= maxSigs) {
printf("That's all folks\n");
exit(EXIT_SUCCESS);
}
}
}
prevClock = clock();
displayTimes("Main: ", TRUE);
}
}
yexiang@ubuntu:<_Sys>$ ./a.out 1 800000 1 0
Elapsed Value Interval
START: 0.00
Main: 0.50 0.50 1.00
ALARM: 1.00 1.00 1.00
Main: 1.00 1.00 1.00
Main: 1.50 0.50 1.00
ALARM: 2.00 1.00 1.00
Main: 2.00 1.00 1.00
Main: 2.50 0.50 1.00
ALARM: 3.00 1.00 1.00
That's all folks
四、實例alarm
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <utime.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <dirent.h>
#include <limits.h>
#include <malloc.h>
#include <signal.h>
#include <setjmp.h>
#include <stdarg.h>
static void sig_alrm(int signo)
{
system("date");
return;
}
int main(void)
{
signal(SIGALRM,sig_alrm);
system("date");
alarm(20);
sleep(5);
printf("%d\n",alarm(5));
pause();
}
// alarm(5) 的時候會清除之前的定時器並且返回之前的剩餘秒數,由於sleep了5秒,剩餘15秒
// 並且5秒後觸發信號,所以時間過去了10秒
yexiang@ubuntu:<_Sys>$ ./a.out
Thu Jan 16 18:59:32 PST 2020
15
Thu Jan 16 18:59:42 PST 2020
// 如果 alarm(5) 改爲 alarm(0) 結果如下:
// 會一直等待,因爲alarm(0) 取消掉了定時器不會觸發信號
// pause又要等待信號執行才往下走,但等不到,所以一直等待
yexiang@ubuntu:<_Sys>$ ./a.out
Thu Jan 16 19:02:12 PST 2020
15