歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網

linux定時器

日期:2017/3/2 17:16:25   编辑: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();
}
}
Copyright © Linux教程網 All Rights Reserved