一,三種時間結構
time_t://seconds
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
二,setitimer()
現在的系統中很多程式不再使用alarm呼叫,而是使用setitimer呼叫來設定定時器,用getitimer來得到定時器的狀態,
這兩個呼叫的宣告格式如下:
#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);
引數:
- 第一個引數which指定定時器型別
- 第二個引數是結構itimerval的一個例項,結構itimerval形式
- 第三個引數可不做處理。
返回值:成功返回0失敗返回-1
該系統呼叫給程式提供了三個定時器,它們各自有其獨有的計時域,當其中任何一個到達,就傳送一個相應的訊號給程式,並使得計時器重新開始。三個計時器由引數which指定,如下所示:
TIMER_REAL:按實際時間計時,計時到達將給程式傳送SIGALRM訊號。
ITIMER_VIRTUAL:僅當程式執行時才進行計時。計時到達將傳送SIGVTALRM訊號給程式。
ITIMER_PROF:當程式執行時和系統為該程式執行動作時都計時。與ITIMER_VIR-TUAL是一對,該定時器經常用來統計程式在使用者態和核心態花費的時間。計時到達將傳送SIGPROF訊號給程式。
定時器中的引數value用來指明定時器的時間,其結構如下:
struct itimerval {
struct timeval it_interval; /* 第一次之後每隔多長時間 */
struct timeval it_value; /* 第一次呼叫要多長時間 */
};
該結構中timeval結構定義如下:
struct timeval {
long tv_sec; /* 秒 */
long tv_usec; /* 微秒,1秒 = 1000000 微秒*/
};
在setitimer 呼叫中,引數ovalue如果不為空,則其中保留的是上次呼叫設定的值。定時器將it_value遞減到0時,產生一個訊號,並將it_value的值設定為it_interval的值,然後重新開始計時,如此往復。當it_value設定為0時,計時器停止,或者當它計時到期,而it_interval 為0時停止。呼叫成功時,返回0;錯誤時,返回-1,並設定相應的錯誤程式碼errno:
EFAULT:引數value或ovalue是無效的指標。
EINVAL:引數which不是ITIMER_REAL、ITIMER_VIRT或ITIMER_PROF中的一個。
示例一:
#include <unistd.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/types.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <signal.h> #include <sys/time.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) void handler(int sig) { printf("recv a sig=%d\n", sig); } int main(int argc, char *argv[]) { if (signal(SIGALRM, handler) == SIG_ERR) ERR_EXIT("signal error"); struct timeval tv_interval = {1, 0}; struct timeval tv_value = {5, 0}; struct itimerval it; it.it_interval = tv_interval; it.it_value = tv_value; setitimer(ITIMER_REAL, &it, NULL); for (;;) pause(); return 0; }
結果:
可以看到第一次傳送訊號是在5s以後,之後每隔一秒傳送一次訊號
示例二:獲得產生時鐘訊號的剩餘時間
#include <unistd.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/types.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <signal.h> #include <sys/time.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) int main(int argc, char *argv[]) { struct timeval tv_interval = {1, 0}; struct timeval tv_value = {1, 0}; struct itimerval it; it.it_interval = tv_interval; it.it_value = tv_value; setitimer(ITIMER_REAL, &it, NULL); int i; for (i=0; i<10000; i++); //第一種方式獲得剩餘時間 struct itimerval oit; setitimer(ITIMER_REAL, &it, &oit);//利用oit獲得剩餘時間產生時鐘訊號 printf("%d %d %d %d\n", (int)oit.it_interval.tv_sec, (int)oit.it_interval.tv_usec, (int)oit.it_value.tv_sec, (int)oit.it_value.tv_usec); //第二種方式獲得剩餘時間 //getitimer(ITIMER_REAL, &it); //printf("%d %d %d %d\n", (int)it.it_interval.tv_sec, (int)it.it_interval.tv_usec, (int)it.it_value.tv_sec, (int)it.it_value.tv_usec); return 0; }
結果:
用第一種方式:
用第二種方式:利用getitimer在不重新設定時鐘的情況下獲取剩餘時間
剩餘時間是指:距離下一次呼叫定時器產生訊號所需時間,這裡由於for迴圈不到一秒就執行完,定時器還來不及產生時鐘訊號,所以有剩餘時間
示例三:每隔一秒發出一個SIGALRM,每隔0.5秒發出一個SIGVTALRM訊號
#include <signal.h> #include <unistd.h> #include <stdio.h> #include <sys/time.h> void sigroutine(int signo) { switch (signo) { case SIGALRM: printf("Catch a signal -- SIGALRM\n "); break; case SIGVTALRM: printf("Catch a signal -- SIGVTALRM\n "); break; } return; } int main() { struct itimerval value,value2; printf("process id is %d\n ",getpid()); signal(SIGALRM, sigroutine); signal(SIGVTALRM, sigroutine); value.it_value.tv_sec = 1; value.it_value.tv_usec = 0; value.it_interval.tv_sec = 1; value.it_interval.tv_usec = 0; setitimer(ITIMER_REAL, &value,NULL); value2.it_value.tv_sec = 0; value2.it_value.tv_usec = 500000; value2.it_interval.tv_sec = 0; value2.it_interval.tv_usec = 500000; setitimer(ITIMER_VIRTUAL, &value2,NULL); for (;;) ; }
結果:
可知確實是沒兩次SIGVTALRM一次SIGALRM