内核的定时机制应用
練習怎樣編寫調用內核的時間測量功能為應用程序測量和精確定時。通過該練習我們可以進一步理解 Linux 內核的定時機制及其數據結構以及怎樣從用戶空間去訪問內核空間的時間數據。
從用戶空間去獲取系統時間數據需要以下基本代碼:
#include <sys/time>struct timeval{ long tv_sec; //從 1970-1-1 12:到現在經過的秒數 long tv_usec;//從從上 1 秒到現在經過的微秒數 } theTime;gettimeofday(&theTime,NULL); //獲取系統時間的系統調用每個進程使用的各種定時器需要 Linux 的內部定時器。使用內部定時器可以跟蹤記錄 3種不同類型的定時機制,它們反映了不同時間的劃分,這些定時機制有各自不同的作用和應用。
它們是 :
? ITIMER_REAL: 反映進程經過的實際時間,這種定時器到時后發 SIGALRM 信號。它與 struct task_struct 結構中的 it_real_value 和 it_real_incr 字段有關。
? ITIMER_VIRTUAL: 反映進程經過的虛擬時間,只有相關進程正在執行時該時間才會增加。這種定時器到時后發 SIGVTALRM 信號。與 struct task_struct 結構中的it_virt_value 和 it_virt_incr 字段有關
? ITIMER_PROF:反映進程經過的虛擬時間加上內核為相關進程執行工作的時間之和。這 種 定 時 器 到 時 后 發 SIGPROF 信 號 。 與 struct task_struct 結 構 中 的it_prof_value 和 it_prof_incr 字段有關。
每個定時器需要周期性的設定一個初始時間值,之后遞減計數到 0 后引發定時中斷,產生超時信號通知對應進程定時器時間到,然后定時器重新從設置的初始值再次開始遞減計數。
三種定時器都使用 setitimer()系統調用進行初始化:
#include <sys/time.h> ? setitimer( int timerType ,//定時器類型 const struct itimerval *value, //定時器初始的和當前的秒數和毫秒數 struct itimerval *oldValue ) struct itimerval{ struct timeval it_it_interval; //下一次定時初值。若為 0 定時器停止 struct timeval it_value //定時器當前值 } ;三種定時器都使用 getitimer()系統調用獲取定時器當前值:
#include <sys/time.h>setitimer( int timerType ,//定時器類型 const struct itimerval *value, //定時器初始的和當前的秒數和毫秒數 struct itimerval *oldValue ) struct itimerval{ struct timeval it_it_interval; //下一次定時初值。若為 0 定時器停止 struct timeval it_value //定時器當前值 } ;首先我們先根據內核的定時機制,來實現一個測試程序運行時間的例子:
程序是監聽用戶ctrl+c按鍵,按下后,打印一次程序從開始運行經歷了多長時間了,下面是我的代碼實現部分:
下面是我的程序的運行截圖:
下面我們再來實現一個鬧鐘的功能,該鬧鐘有一個特點就是可以精確到微秒級,就是使用我們的定時機制.用戶輸入經過多少個小時,多少分鐘,多少秒,多少毫秒,多少微秒之后提醒該用戶.下面是我的程序實現部分:
/*** Function: 實現一個微秒級的鬧鐘* 使用系統的定時器功能可以使鬧鐘精確到微秒級別**/#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <sys/time.h>//信號SIGALRM的處理函數原型 static void sigreal(void);//定時器 struct itimerval realt;//設置程序是否繼續運行 static int is_run = 1;int main() {int h,m,s,ms,us;printf("Please enter the hours:minutes:seconds:ms:us after!\n");scanf("%d:%d:%d:%d:%d",&h,&m,&s,&ms,&us);int seconds = h * 3600 + m * 60 + s;int uSeconds = ms * 1000 + us;//定時器設置realt.it_interval.tv_sec = seconds;realt.it_interval.tv_usec = uSeconds;realt.it_value.tv_sec = seconds;realt.it_value.tv_usec = uSeconds;signal(SIGALRM,sigreal);setitimer(ITIMER_REAL,&realt,NULL);while(is_run){}printf("Time over!!\n");return 0; }//收到時間到達的信號之后,結束程序的運行 static void sigreal(void) {is_run = 0; }下面是程序的運行截圖:
最后一個例子,我們使用父進程創建了兩個子進程,這三個進程分別運算不同級數的非波那且數列,最后打印出每一個進程各自用了多長時間.
下面是代碼實現:
/*** Function : 測試并發進程執行中的各種時間* 給定3個非波納且數列數值,可選在36-45之間* Author : 陳洪波*/#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <signal.h> #include <sys/time.h>//父進程的3個定時器中斷處理函數原型 static void psig_real(void); static void psig_virtual(void); static void psig_prof(void);//子進程1的三個定時中斷處理函數原型 static void c1sig_real(void); static void c1sig_virtual(void); static void c1sig_prof(void);//子進程2的3個定時器中斷處理函數原型 static void c2sig_real(void); static void c2sig_virtual(void); static void c2sig_prof(void);//非波納且數列函數原型 long unsigned int fibonnacci(unsigned int n);//記錄3種定時的秒數的變量 static long p_real_secs = 0,c1_real_secs = 0,c2_real_secs = 0; static long p_virtual_secs = 0,c1_virtual_secs = 0,c2_virtual_secs = 0; static long p_prof_secs = 0,c1_prof_secs = 0,c2_prof_secs = 0;//記錄3種定時的毫秒秒數的結構變量 static struct itimerval p_realt,c1_realt,c2_realt; static struct itimerval p_virtt,c1_virtt,c2_virtt; static struct itimerval p_proft,c1_proft,c2_proft;int main(int argc,char **argv) {long unsigned fib = 0;pid_t pid1,pid2;unsigned int fibarg;int status;int i;if(argc < 3){printf("Usage: testing arg1 arg2 and arg3!\n");return 1; } //父進程設置3中定時處理函數入口signal(SIGALRM,psig_real);signal(SIGVTALRM,psig_virtual);signal(SIGPROF,psig_prof);//初始化父進程3種時間定時器//進程實際經過的時間p_realt.it_interval.tv_sec = 9;p_realt.it_interval.tv_usec = 999999;p_realt.it_value.tv_sec = 9;p_realt.it_value.tv_usec = 999999;setitimer(ITIMER_REAL,&p_realt,NULL);//進程經過的虛擬時間,只有相關進程正在執行時該時間才fibonnacci(unsigned int n);會增加p_virtt.it_interval.tv_sec = 9;p_virtt.it_interval.tv_usec = 999999;p_virtt.it_value.tv_sec = 9;p_virtt.it_value.tv_usec = 999999;setitimer(ITIMER_VIRTUAL,&p_virtt,NULL);//反映進程經過的虛擬時間加上內核為相關進程執行工作的時間之和p_proft.it_interval.tv_sec = 9;p_proft.it_interval.tv_usec = 999999;p_proft.it_value.tv_sec = 9;p_proft.it_value.tv_usec = 999999;setitimer(ITIMER_PROF,&p_proft,NULL);pid1 = fork();if(pid1 == 0){//子進程1設置3中定時處理入口signal(SIGALRM,c1sig_real);signal(SIGVTALRM,c1sig_virtual);signal(SIGPROF,c1sig_prof);//子進程的3種時間定時器c1_realt.it_interval.tv_sec = 9;c1_realt.it_interval.tv_usec = 999999;c1_realt.it_value.tv_sec = 9;c1_realt.it_value.tv_usec = 999999;setitimer(ITIMER_REAL,&c1_realt,NULL);c1_virtt.it_interval.tv_sec = 9;c1_virtt.it_interval.tv_usec = 999999;c1_virtt.it_value.tv_sec = 9;c1_virtt.it_value.tv_usec = 999999;setitimer(ITIMER_VIRTUAL,&c1_virtt,NULL);c1_proft.it_interval.tv_sec = 9;c1_proft.it_interval.tv_usec = 999999;c1_proft.it_value.tv_sec = 9;c1_proft.it_value.tv_usec = 999999;setitimer(ITIMER_PROF,&c1_proft,NULL);//子進程1開始計算fibfib = fibonnacci(atoi(argv[1]));//打印子進程1所花費的3種時間值getitimer(ITIMER_REAL,&c1_realt);printf("Child1 fib=%ld\n Child1 Real Time=%ld Sec %ld Msec\n",fib,c1_real_secs + 9 - c1_realt.it_value.tv_sec,(999999-c1_realt.it_value.tv_usec)/1000);getitimer(ITIMER_VIRTUAL,&c1_virtt);printf("Child1 Virtual Time=%ld sec %ld Msec\n",c1_virtual_secs+9-c1_virtt.it_value.tv_sec,(999999-c1_virtt.it_value.tv_usec)/1000);getitimer(ITIMER_PROF,&c1_proft);printf("Child1 Prof Time=%ld sec %ld Msec\n\n",c1_prof_secs+9-c1_proft.it_value.tv_sec,(999999-c1_proft.it_value.tv_usec)/1000);}else if((pid2=fork()) == 0){//子進程2設置3中定時處理入口signal(SIGALRM,c2sig_real);signal(SIGVTALRM,c2sig_virtual);signal(SIGPROF,c2sig_prof);//子進程2的3種時間定時器c2_realt.it_interval.tv_sec = 9;c2_realt.it_interval.tv_usec = 999999;c2_realt.it_value.tv_sec = 9;c2_realt.it_value.tv_usec = 999999;setitimer(ITIMER_REAL,&c2_realt,NULL);c2_virtt.it_interval.tv_sec = 9;c2_virtt.it_interval.tv_usec = 999999;c2_virtt.it_value.tv_sec = 9;c2_virtt.it_value.tv_usec = 999999;setitimer(ITIMER_VIRTUAL,&c2_virtt,NULL);c2_proft.it_interval.tv_sec = 9;c2_proft.it_interval.tv_usec = 999999;c2_proft.it_value.tv_sec = 9;c2_proft.it_value.tv_usec = 999999;setitimer(ITIMER_PROF,&c2_proft,NULL);//子進程2開始計算fibfib = fibonnacci(atoi(argv[2]));//打印子進程2所花費的3種時間值getitimer(ITIMER_REAL,&c2_realt);printf("Child2 fib=%ld\n Child2 Real Time=%ld Sec %ld Msec\n",fib,c2_real_secs + 9 - c2_realt.it_value.tv_sec,(999999-c2_realt.it_value.tv_usec)/1000);getitimer(ITIMER_VIRTUAL,&c2_virtt);printf("Child2 Virtual Time=%ld sec %ld Msec\n",c2_virtual_secs+9-c2_virtt.it_value.tv_sec,(999999-c2_virtt.it_value.tv_usec)/1000);getitimer(ITIMER_PROF,&c2_proft);printf("Child2 Prof Time=%ld sec %ld Msec\n\n",c2_prof_secs+9-c2_proft.it_value.tv_sec,(999999-c2_proft.it_value.tv_usec)/1000);}else{//父進程開始計算fibfib = fibonnacci(atoi(argv[3]));//打印父進程所花費的3種時間值getitimer(ITIMER_REAL,&p_realt);printf("Parent fib=%ld\n Parent Real Time=%ld Sec %ld Msec\n",fib,p_real_secs + 9 - p_realt.it_value.tv_sec,(999999-p_realt.it_value.tv_usec)/1000);getitimer(ITIMER_VIRTUAL,&p_virtt);printf("Parent Virtual Time=%ld sec %ld Msec\n",p_virtual_secs+9-p_virtt.it_value.tv_sec,(999999-p_virtt.it_value.tv_usec)/1000);getitimer(ITIMER_PROF,&p_proft);printf("Parent Prof Time=%ld sec %ld Msec\n\n",p_prof_secs+9-p_proft.it_value.tv_sec,(999999-p_proft.it_value.tv_usec)/1000);//等待子進程結束waitpid(pid1,&status,0);waitpid(pid2,&status,0);} }//父進程的3個定時中斷處理函數 static void psig_real(void) {p_real_secs += 10; }static void psig_virtual(void) {p_virtual_secs += 10; }static void psig_prof(void) {p_prof_secs += 10; }//子進程1的3個中斷處理函數 static void c1sig_real(void) {c1_real_secs += 10; }static void c1sig_virtual(void) {c1_virtual_secs += 10; }static void c1sig_prof(void) {c1_prof_secs += 10; }//子進程2的3個中斷處理函數 static void c2sig_real(void) {c2_real_secs += 10; }static void c2sig_virtual(void) {c2_virtual_secs += 10; }static void c2sig_prof(void) {c2_prof_secs += 10; }//非波納且的遞歸實現 long unsigned int fibonnacci(unsigned int n) {if(n==1 || n==2)return 1;return fibonnacci(n-1)+fibonnacci(n-2); }下面是程序的運行截圖:
轉載于:https://www.cnblogs.com/bobo1223/p/7287602.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
- 上一篇: Objective-C 编码规范
- 下一篇: Git 远程操作详解