LInux下幾種定時器的比較和使用


在數據通信過程中,會遇到對數據發送時間的格式要求。所以要在應用中根據實際要求選擇不同的定時器,就要考慮到幾種應用定時器的特點。

定時器文章參考 

一般而言有,

1、sleep,usleep和nanosleep

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定時器是阻塞的,在等待時間到來之前什么都不做。要定時可以考慮再開一個線程來做。

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM