linux定時器


  我們常常有設置系統在某一時間執行相應動作的需求,比如設置電腦什么時候自動鎖屏,什么時候自動關機,設置應用程序什么時候自動運行,什么時候自動退出。這些與時間相關的功能,都需要依靠操作系統中的定時器來實現。

  linux中定時器的使用原理很簡單,你只需設置一個超時時間和相應的執行函數,系統就會在超時的時候執行一開始設置的函數。超時的概念有點模糊,它指的是你設定一個時間,如果當前的時間超過了你設定的時間,那就超時了。比如說,你設置五分鍾后系統自動關機,系統會記住五分鍾后的具體時間,也就是當前時間再加上五分鍾。過了五分鍾后,系統當前時間已經比剛才設置的具體時間大了,出現超時,於是運行超時行為。

  在linux中,使用alarm函數可以設置一個定時器,當定時器超時的時候,會產生SIGALRM信號。因此,要設置超時行為,就得在SIGALRM信號上設置相應的函數。

  包含頭文件:#include <unistd.h>

  函數原型:unsigned int alarm(unsigned int seconds);

  具體例子如下:  

 

#include <stdio.h>
#include <signal.h> 
#include <unistd.h>

void SigFun(int signo){
    printf("SigFun is running\n");
}

int main(){
    if(signal(SIGALRM, SigFun) == SIG_ERR){
        perror("signal\n");
     return -1; } alarm(
5); pause(); }

 

  在linux中,一個進程只能有一個定時器,因此當一個進程需要設置多個定時行為時,需要采取相應的措施,使得一個定時器可以實現多個定時。主要的方法有兩種,一種叫時間鏈,一種叫時間堆。

  時間鏈是將所有定時行為以鏈表的方式連在一起,同時在進程中維護一個固定時間超時的定時器。當定時器超時的時候,檢查鏈表上所有的行為是否超時,如果有超時的行為,則運行其行為,並將其從鏈表中刪除。這用方法最大的壞處就是需要固定時間遍歷整個鏈表,造成了比較大的開銷。

  時間堆是將所有定時行為以最小堆的方式組織起來,並且在進程中維護一個以堆頂為超時時間的定時器。當定時器超時時,檢查堆頂行為是否超時,如果超時,則運行該行為,並將其從堆頂刪除,接着繼續檢查;如果堆頂行為未超時,則用其超時時間繼續設置定時器。時間堆不用固定時間去檢查所有定時行為,只需在超時的時候運行相應的超時行為,效率比時間鏈高。

  在linux中,alarm函數是以秒計時的,當有時我們需要更小的時間單位去設置行為,比如毫秒,應該怎么辦呢?linux提供setitimer函數,可以提供更精確的定時器。

  包含頭文件:#include <sys/time.h>

  函數原型:int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);

  參數:

  int which有三種選擇:

  ITIMER_REAL:decrements in real time, and deliversSIGALRM upon expiration.

  ITIMER_VIRTUAL:decrements only  when  the  process  is  executing,  anddeliversSIGVTALRM upon expiration.

  ITIMER_PROF:decrements  both  when the process executes and when the system is executing on behalf of the  process. Coupledwith  ITIMER_VIRTUAL, this timer is usually used to profile the time spent by the application in user and  kernel space.  SIGPROF is delivered

  const struct itimerval *new_value的數據結構如下:

struct itimerval {
    struct timeval it_interval; /* 第一次超時以后每次超時的時間 */
    struct timeval it_value; /* 第一次超時的時間 */
};
struct timeval {
    long tv_sec; /* seconds */
    long tv_usec; /* microseconds */
};

  struct itimerval *old_value是原來設置的時間,如果不需要用到,可以用NULL

  成功調用返回0,失敗返回-1。

  具體例子如下:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>

void SigFun(int signo){
    printf("SigFun is running\n");    
}

int main(){
    if(signal(SIGALRM, SigFun) == SIG_ERR){
        perror("signal\n");
        return -1;
    }
    
    struct itimerval tv;
    tv.it_value.tv_usec = 500000;
    tv.it_value.tv_sec = 0;
    tv.it_interval.tv_usec = 300000;
    tv.it_interval.tv_sec = 0;
    
    if(setitimer(ITIMER_REAL, &tv, NULL) != 0){
        perror("setitimer\n");
        return -1;
    }

    while(true){
        pause();
    }
}

 


免責聲明!

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



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