在數據通信過程中,會遇到對數據發送時間的格式要求。所以要在應用中根據實際要求選擇不同的定時器,就要考慮到幾種應用定時器的特點。
定時器文章參考
一般而言有,
sleep()和nanosleep()都是使進程睡眠一段時間后被喚醒,但是二者的實現完全不同。
Linux中並沒有提供系統調用sleep(),sleep()是在庫函數中實現的,它是通過調用alarm()來設定報警時間,調用sigsuspend()將進程掛起在信號SIGALARM上,sleep()只能精確到秒級上。
nanosleep()則是Linux中的系統調用,它是使用定時器來實現的,該調用使調用進程睡眠,並往定時器隊列上加入一個timer_list型定時器,time_list結構里包括喚醒時間以及喚醒后執行的函數,通過nanosleep()加入的定時器的執行函數僅僅完成喚醒當前進程的功能。系統通過一定的機制定時檢查這些隊列(比如通過系統調用陷入核心后,從核心返回用戶態前,要檢查當前進程的時間片是否已經耗盡,如果是則調用schedule()函數重新調度,該函數中就會檢查定時器隊列,另外慢中斷返回前也會做此檢查),如果定時時間已超過,則執行定時器指定的函數喚醒調用進程。當然,由於系統時間片可能丟失,所以nanosleep()精度也不是很高。
alarm()也是通過定時器實現的,但是其精度只精確到秒級,另外,它設置的定時器執行函數是在指定時間向當前進程發送SIGALRM信號。
2、使用信號量SIGALRM + alarm()
alarm方式雖然很好,但這種方式的精度能達到1秒,是無法低於1秒的精度。其中利用了*nix系統的信號量機制,首先注冊信號量SIGALRM處理函數,調用alarm(),設置定時長度,代碼如下:
//設置一個1s延時信號,再注冊一個
#include <stdio.h> #include <signal.h> void timer(int sig) { if(SIGALRM == sig) { printf("timer\n"); alarm(1); //重新繼續定時1s } return ; } int main() { signal(SIGALRM, timer); //注冊安裝信號 alarm(1); //觸發定時器 getchar(); return 0; }
3、使用RTC機制
RTC機制利用系統硬件提供的Real Time Clock機制,通過讀取RTC硬件/dev/rtc,通過ioctl()設置RTC頻率,這種方式比較方便,利用了系統硬件提供的RTC,精度可調,而且非常高代碼如下:
#include <stdio.h> #include <linux/rtc.h> #include <sys/ioctl.h> #include <sys/time.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <stdlib.h> int main(int argc, char* argv[]) { unsigned long i = 0; unsigned long data = 0; int retval = 0; int fd = open ("/dev/rtc", O_RDONLY); if(fd < 0) { perror("open"); exit(errno); } /*Set the freq as 4Hz*/ if(ioctl(fd, RTC_IRQP_SET, 1) < 0) { perror("ioctl(RTC_IRQP_SET)"); close(fd); exit(errno); } /* Enable periodic interrupts */ if(ioctl(fd, RTC_PIE_ON, 0) < 0) { perror("ioctl(RTC_PIE_ON)"); close(fd); exit(errno); } for(i = 0; i < 100; i++) { if(read(fd, &data, sizeof(unsigned long)) < 0) { perror("read"); close(fd); exit(errno); } printf("timer\n"); } /* Disable periodic interrupts */ ioctl(fd, RTC_PIE_OFF, 0); close(fd); return 0; }
該種方式要求系統有RTC設備,我們的1860有兩個RTC,用的是電源管理模塊的LC1160中的RTC,但是驅動中沒有關於RTC_IRQP_SET控制字的支持,需要后期添加驅動實現。
4、使用select()
能精確到1us,目前精確定時的最流行方案。通過使用select(),來設置定時器;原理利用select()方法的第5個參數,第一個參數設置為0,三個文件描述符集都設置為NULL,第5個參數為時間結構體,代碼如下:
#include <sys/time.h> #include <sys/select.h> #include <time.h> #include <stdio.h> /*seconds: the seconds; mseconds: the micro seconds*/ void setTimer(int seconds, int mseconds) { struct timeval temp; temp.tv_sec = seconds; temp.tv_usec = mseconds; select(0, NULL, NULL, NULL, &temp); printf("timer\n"); return ; } int main() { int i; for(i = 0 ; i < 100; i++) setTimer(1, 0); return 0; }
結果是,每隔1s打印一次,打印100次。
select定時器是阻塞的,在等待時間到來之前什么都不做。要定時可以考慮再開一個線程來做。