1.時鐘相關的API函數原型
#include <unistd.h>
unsigned int sleep(unsigned int seconds);
unsigned int alarm(unsigned int seconds);
int usleep(useconds_t usec);
#include <sys/time.h>
int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimerval *new_value,
struct itimerval *old_value);
struct itimerval {
struct timeval it_interval; /* next value */
struct timeval it_value; /* current value */
};
struct timeval {
time_t tv_sec; /* seconds */
SUSEconds_t tv_usec; /* microseconds */
};
Linux內核時鐘與定時器的實現 http://www.linuxidc.com/Linux/2012-04/59055.htm
嵌入式Linux:系統時鐘的寄存器 http://www.linuxidc.com/Linux/2012-07/66787.htm
clk_get函數實現,Linux內核時鐘框架 http://www.linuxidc.com/Linux/2012-03/56418.htm
Linux 實時時鐘(RTC)驅動 http://www.linuxidc.com/Linux/2011-10/44430.htm
Linux下S3C2440 RTC實時時鐘驅動配置與修改 http://www.linuxidc.com/Linux/2011-09/43691.htm
2.sleep的實現
sleep其實大家應該都不陌生,很多語言中都有相應的實現,其作用就是設置一個時延,等待時延,掛起進程。等待時間到達了就恢復進程的運行。在linux中sleep的是實現是使用alarm這個API函數來實現的。實現步驟如下:
一:為SIGALRM設置一個處理函數(SIGALRM是一個時鐘信號,時間到了內核就會向進程發送SIGALRM信號)
二:.調用alarm(num_seconds);設置定時器
三:調用pause掛起進程。
這就是一個sleep函數的處理過程,代碼如下:
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
void wakeup(int);
void do_thing();
int main ( int argc, char *argv[] )
{
printf("about to sleep for seconds\n");
signal(SIGALRM,wakeup);
alarm(4);
pause();
printf("Morning so son?\n");
return EXIT_SUCCESS;
}
/* ---------- end of function main ---------- */
void wakeup(int signum)
{
printf("Alarm received from kernel\n");
}
alarm是一個linux下的計時器,它的第一個用途就是用來作為時延,另一個用途是調度一個在將來某個時刻發生的動作同時做些其他事情。
通過alarm設置計時器,然後繼續做別的事情,當計時器到達0,信號發送,處理函數被調用。
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
void do_thing();
int main ( int argc, char *argv[] )
{
printf("about to sleep for seconds\n");
signal(SIGALRM,do_thing);
alarm(4);
while(1){
sleep(2);
printf("繼續執行\n");
}
return EXIT_SUCCESS;
}
/* ---------- end of function main ---------- */
void do_thing()
{
printf("4秒後執行的\n");
}
sleep,alarm都只能處理秒級的時延和計時器。在linux中提供了ulseep函數提供一個精度更高的時延
3.進程的三個計時器
每一個進程都有三個計時器,分別是:
ITIMER_REAL 用來真實時間的。如果手表記錄一樣。當這個計時器時間用盡就會發送SIGLRM消息
ITIMER_VIRTUAL 這個計時器只有在用戶運行在用戶態的時候才計時
ITIMER_PROF 這個計時器用於進程運行在用戶態或由該進程調用而陷入核心態時計時。
三個計時器,難道計算機又三個時鐘嘛?其實不然,計算機只有一個時鐘。其工作方式是每個進程都有自己的計數器,cpu每隔一個時間片就遍歷一下所有進程為每一個進程的計時器做遞減。
4.間隔計時器編程
間隔計時器和普通的計時器不同,這個計時器有兩個值,一個是初始時間間隔,另外一個是重復間隔設置。下面是一個間隔計時器的例子:
#include<stdio.h>
#include<sys/time.h>
#include<signal.h>
#include<stdlib.h>
void countdown(int);
int set_ticker(int);
int main ( int argc, char *argv[] )
{
//設置信號處理函數
signal(SIGALRM,countdown);
//設置計時器
if(set_ticker(500) == -1)
perror("set_ticker:");
else
//進程繼續運行
while(1)
done_other_thing();
return EXIT_SUCCESS;
}
/* ---------- end of function main ---------- */
void done_other_thing()
{
sleep(1);
printf("*****\n");
}
void countdown (int signum)
{
static int num=10;
printf("%d..",num--);
fflush(stdout);
if(num<0){
printf("DONE! \n");
exit(0);
}
}
/* ----- end of function countdown ----- */
int set_ticker(int n_msecs)
{
struct itimerval new_timeset;
long n_sec,n_usecs;
n_sec = n_msecs / 1000;
n_usecs = (n_msecs % 1000) *1000L;
new_timeset.it_interval.tv_sec = n_sec;
new_timeset.it_interval.tv_usec = n_usecs;
new_timeset.it_value.tv_sec = n_sec;
new_timeset.it_value.tv_usec = n_usecs;
return setitimer(ITIMER_REAL,&new_timeset,NULL);
}
上面的運行過程如下:首先設置了信號處理函數countdown,然後設置了計時器,初始值是500毫秒也就是500毫秒後計時器時間到,重復間隔也是500。初始500毫秒到達後,又會重新設置計時器為500毫秒。設置好計時器後程序繼續向下運行做其他時間了。500毫秒到了後就會出發countdown函數。這個函數會打印數字,並遞減靜態變量num的值,重復執行十次後num的值就小於0了。然後再次出發countdown的時候就退出整個程序了。