内核的定时机制应用
練習(xí)怎樣編寫(xiě)調(diào)用內(nèi)核的時(shí)間測(cè)量功能為應(yīng)用程序測(cè)量和精確定時(shí)。通過(guò)該練習(xí)我們可以進(jìn)一步理解 Linux 內(nèi)核的定時(shí)機(jī)制及其數(shù)據(jù)結(jié)構(gòu)以及怎樣從用戶空間去訪問(wèn)內(nèi)核空間的時(shí)間數(shù)據(jù)。
從用戶空間去獲取系統(tǒng)時(shí)間數(shù)據(jù)需要以下基本代碼:
#include <sys/time>struct timeval{ long tv_sec; //從 1970-1-1 12:到現(xiàn)在經(jīng)過(guò)的秒數(shù) long tv_usec;//從從上 1 秒到現(xiàn)在經(jīng)過(guò)的微秒數(shù) } theTime;gettimeofday(&theTime,NULL); //獲取系統(tǒng)時(shí)間的系統(tǒng)調(diào)用每個(gè)進(jìn)程使用的各種定時(shí)器需要 Linux 的內(nèi)部定時(shí)器。使用內(nèi)部定時(shí)器可以跟蹤記錄 3種不同類型的定時(shí)機(jī)制,它們反映了不同時(shí)間的劃分,這些定時(shí)機(jī)制有各自不同的作用和應(yīng)用。
它們是 :
? ITIMER_REAL: 反映進(jìn)程經(jīng)過(guò)的實(shí)際時(shí)間,這種定時(shí)器到時(shí)后發(fā) SIGALRM 信號(hào)。它與 struct task_struct 結(jié)構(gòu)中的 it_real_value 和 it_real_incr 字段有關(guān)。
? ITIMER_VIRTUAL: 反映進(jìn)程經(jīng)過(guò)的虛擬時(shí)間,只有相關(guān)進(jìn)程正在執(zhí)行時(shí)該時(shí)間才會(huì)增加。這種定時(shí)器到時(shí)后發(fā) SIGVTALRM 信號(hào)。與 struct task_struct 結(jié)構(gòu)中的it_virt_value 和 it_virt_incr 字段有關(guān)
? ITIMER_PROF:反映進(jìn)程經(jīng)過(guò)的虛擬時(shí)間加上內(nèi)核為相關(guān)進(jìn)程執(zhí)行工作的時(shí)間之和。這 種 定 時(shí) 器 到 時(shí) 后 發(fā) SIGPROF 信 號(hào) 。 與 struct task_struct 結(jié) 構(gòu) 中 的it_prof_value 和 it_prof_incr 字段有關(guān)。
每個(gè)定時(shí)器需要周期性的設(shè)定一個(gè)初始時(shí)間值,之后遞減計(jì)數(shù)到 0 后引發(fā)定時(shí)中斷,產(chǎn)生超時(shí)信號(hào)通知對(duì)應(yīng)進(jìn)程定時(shí)器時(shí)間到,然后定時(shí)器重新從設(shè)置的初始值再次開(kāi)始遞減計(jì)數(shù)。
三種定時(shí)器都使用 setitimer()系統(tǒng)調(diào)用進(jìn)行初始化:
#include <sys/time.h> ? setitimer( int timerType ,//定時(shí)器類型 const struct itimerval *value, //定時(shí)器初始的和當(dāng)前的秒數(shù)和毫秒數(shù) struct itimerval *oldValue ) struct itimerval{ struct timeval it_it_interval; //下一次定時(shí)初值。若為 0 定時(shí)器停止 struct timeval it_value //定時(shí)器當(dāng)前值 } ;三種定時(shí)器都使用 getitimer()系統(tǒng)調(diào)用獲取定時(shí)器當(dāng)前值:
#include <sys/time.h>setitimer( int timerType ,//定時(shí)器類型 const struct itimerval *value, //定時(shí)器初始的和當(dāng)前的秒數(shù)和毫秒數(shù) struct itimerval *oldValue ) struct itimerval{ struct timeval it_it_interval; //下一次定時(shí)初值。若為 0 定時(shí)器停止 struct timeval it_value //定時(shí)器當(dāng)前值 } ;首先我們先根據(jù)內(nèi)核的定時(shí)機(jī)制,來(lái)實(shí)現(xiàn)一個(gè)測(cè)試程序運(yùn)行時(shí)間的例子:
程序是監(jiān)聽(tīng)用戶ctrl+c按鍵,按下后,打印一次程序從開(kāi)始運(yùn)行經(jīng)歷了多長(zhǎng)時(shí)間了,下面是我的代碼實(shí)現(xiàn)部分:
下面是我的程序的運(yùn)行截圖:
下面我們?cè)賮?lái)實(shí)現(xiàn)一個(gè)鬧鐘的功能,該鬧鐘有一個(gè)特點(diǎn)就是可以精確到微秒級(jí),就是使用我們的定時(shí)機(jī)制.用戶輸入經(jīng)過(guò)多少個(gè)小時(shí),多少分鐘,多少秒,多少毫秒,多少微秒之后提醒該用戶.下面是我的程序?qū)崿F(xiàn)部分:
/*** Function: 實(shí)現(xiàn)一個(gè)微秒級(jí)的鬧鐘* 使用系統(tǒng)的定時(shí)器功能可以使鬧鐘精確到微秒級(jí)別**/#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <sys/time.h>//信號(hào)SIGALRM的處理函數(shù)原型 static void sigreal(void);//定時(shí)器 struct itimerval realt;//設(shè)置程序是否繼續(xù)運(yùn)行 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;//定時(shí)器設(shè)置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; }//收到時(shí)間到達(dá)的信號(hào)之后,結(jié)束程序的運(yùn)行 static void sigreal(void) {is_run = 0; }下面是程序的運(yùn)行截圖:
最后一個(gè)例子,我們使用父進(jìn)程創(chuàng)建了兩個(gè)子進(jìn)程,這三個(gè)進(jìn)程分別運(yùn)算不同級(jí)數(shù)的非波那且數(shù)列,最后打印出每一個(gè)進(jìn)程各自用了多長(zhǎng)時(shí)間.
下面是代碼實(shí)現(xiàn):
/*** Function : 測(cè)試并發(fā)進(jìn)程執(zhí)行中的各種時(shí)間* 給定3個(gè)非波納且數(shù)列數(shù)值,可選在36-45之間* Author : 陳洪波*/#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <signal.h> #include <sys/time.h>//父進(jìn)程的3個(gè)定時(shí)器中斷處理函數(shù)原型 static void psig_real(void); static void psig_virtual(void); static void psig_prof(void);//子進(jìn)程1的三個(gè)定時(shí)中斷處理函數(shù)原型 static void c1sig_real(void); static void c1sig_virtual(void); static void c1sig_prof(void);//子進(jìn)程2的3個(gè)定時(shí)器中斷處理函數(shù)原型 static void c2sig_real(void); static void c2sig_virtual(void); static void c2sig_prof(void);//非波納且數(shù)列函數(shù)原型 long unsigned int fibonnacci(unsigned int n);//記錄3種定時(shí)的秒數(shù)的變量 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種定時(shí)的毫秒秒數(shù)的結(jié)構(gòu)變量 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; } //父進(jìn)程設(shè)置3中定時(shí)處理函數(shù)入口signal(SIGALRM,psig_real);signal(SIGVTALRM,psig_virtual);signal(SIGPROF,psig_prof);//初始化父進(jìn)程3種時(shí)間定時(shí)器//進(jìn)程實(shí)際經(jīng)過(guò)的時(shí)間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);//進(jìn)程經(jīng)過(guò)的虛擬時(shí)間,只有相關(guān)進(jìn)程正在執(zhí)行時(shí)該時(shí)間才fibonnacci(unsigned int n);會(huì)增加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);//反映進(jìn)程經(jīng)過(guò)的虛擬時(shí)間加上內(nèi)核為相關(guān)進(jìn)程執(zhí)行工作的時(shí)間之和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){//子進(jìn)程1設(shè)置3中定時(shí)處理入口signal(SIGALRM,c1sig_real);signal(SIGVTALRM,c1sig_virtual);signal(SIGPROF,c1sig_prof);//子進(jìn)程的3種時(shí)間定時(shí)器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);//子進(jìn)程1開(kāi)始計(jì)算fibfib = fibonnacci(atoi(argv[1]));//打印子進(jìn)程1所花費(fèi)的3種時(shí)間值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){//子進(jìn)程2設(shè)置3中定時(shí)處理入口signal(SIGALRM,c2sig_real);signal(SIGVTALRM,c2sig_virtual);signal(SIGPROF,c2sig_prof);//子進(jìn)程2的3種時(shí)間定時(shí)器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);//子進(jìn)程2開(kāi)始計(jì)算fibfib = fibonnacci(atoi(argv[2]));//打印子進(jìn)程2所花費(fèi)的3種時(shí)間值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{//父進(jìn)程開(kāi)始計(jì)算fibfib = fibonnacci(atoi(argv[3]));//打印父進(jìn)程所花費(fèi)的3種時(shí)間值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);//等待子進(jìn)程結(jié)束waitpid(pid1,&status,0);waitpid(pid2,&status,0);} }//父進(jìn)程的3個(gè)定時(shí)中斷處理函數(shù) 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; }//子進(jìn)程1的3個(gè)中斷處理函數(shù) 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; }//子進(jìn)程2的3個(gè)中斷處理函數(shù) 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; }//非波納且的遞歸實(shí)現(xiàn) long unsigned int fibonnacci(unsigned int n) {if(n==1 || n==2)return 1;return fibonnacci(n-1)+fibonnacci(n-2); }下面是程序的運(yùn)行截圖:
轉(zhuǎn)載于:https://www.cnblogs.com/bobo1223/p/7287602.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
- 上一篇: Objective-C 编码规范
- 下一篇: Git 远程操作详解