1. 程式人生 > >linux核心程式設計實驗三

linux核心程式設計實驗三

核心的定時機制實驗

問題 A
使用ITIMER_REAL型定時器實現一個gettimeofday(),將它設定為每秒產生一個訊號,
並計算已經經過的秒數。
問題 B
使用以上實現的 gettimeofday()實現一個精確到微秒級的“鬧鐘”。
問題 C
實現以上一個父程序和兩個子程序併發遞迴計算不同項數的fibonacci序列的程式,
分析每個程序三種類型定時器測出的時間關係。

解決問題A
一直被實現一個gettimeofday()這句話困惑,在不停思考如何實現這個方法。這是一個系統呼叫,由作業系統提供,涉及底層計算機架構的知識。這與我們的實驗目的不符。gettimeofday函式用來獲取系統時間的秒數、微秒數。通常可以在程式執行開始前獲得一次時間,程式執行結束後獲得一次時間,通過差的計算得到程式執行時間。(以1970年1月1日0時0分0秒為時間起點)
那麼問題A的目的就明確了,就是實現為程式記時的功能,但不使用gettimeofday,要求使用setitimer和getitimer而已。
首先需要寫一個SIGALRM訊號處理函式,該函式用來計算時間,通過signal函式繫結。然後setitimer()。執行程式。最後通過getitimer獲得計時器的值,與前面的時間一起計算出程式最終用時。

解決問題B
鬧鐘大家都用過,初始設定一個時間,到時間之後對使用者產生提醒。因此,首先需要使用者輸入精確的時間,然後使用問題A的步驟繫結訊號處理,設定計時器,超時之後,提醒使用者時間到。獲取系統當前時間並轉化成微秒時間戳,然後將使用者設定的時間轉換成微秒時間戳,計算差值。設定計時器,讓計時器只工作一次即可。

解決問題C
fork兩個程序與父程序一起求fibonacci數。與問題A類似,只不過需要使用三種定時器。求fibonacci數時函式儘量選擇遞迴,數不可太大,也不能過小,20-40之間即可,可以讓實驗結果更加明顯。

p_realt.it_value.tv_sec = 9;
p_realt.it_value.tv_usec = 999999;
p_realt.it_interval.tv_sec = 9;
p_realt.it_interval.tv_usec = 999999;
這裡其實是9秒999999微秒,但是按照10秒計算,理論上誤差1微秒,實際上由於計算機執行速度的問題,這點誤差可忽略。
當p_realt.it_interval.tv_sec = 9;p_realt.it_interval.tv_usec = 999999;
設定為0時,計時器只工作一次,否則計時器迴圈工作,it_value的值將變成it_interval。

程式碼如下:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h> //for time()
#include <sys/time.h> //for itimeval
#include <sys/types.h> //for pid_t
#include <sys/wait.h> //for waitpid

void psig_real(int signum); //父程序3個訊號處理函式
void psig_virtual(int signum); void psig_prof(int signum); void c1sig_real(int signum); //子程序1的3個訊號處理 void c1sig_virtual(int signum); void c1sig_prof(int signum); void c2sig_real(int signum); //子程序2的3個訊號處理 void c2sig_virtual(int signum); void c2sig_prof(int signum); long fibonacci(unsigned int n); //求斐波那契 //記時變數 long p_real_secs=0,c1_real_secs=0,c2_real_secs=0; long p_virtual_secs=0,c1_virtual_secs=0,c2_virtual_secs=0; long p_prof_secs= 0,c1_prof_secs=0, c2_prof_secs=0; //計時器結構體 struct itimerval p_realt, c1_realt, c2_realt; struct itimerval p_virtt, c1_virtt, c2_virtt; struct itimerval p_proft, c1_proft, c2_proft; //part A的訊號處理 void psig_real_gettime(int signum) { p_real_secs += 1; } //實現具有gettimeofday功能 ,接收一個函式 void mygettimeofday(unsigned int i,long (*timefunction)(unsigned int)) { signal(SIGALRM,psig_real_gettime); p_realt.it_value.tv_sec = 0; //0 sec p_realt.it_value.tv_usec = 999999; //999999 usec p_realt.it_interval.tv_sec = 0; p_realt.it_interval.tv_usec = 999999; setitimer(ITIMER_REAL,&p_realt,NULL); timefunction(i); getitimer(ITIMER_REAL,&p_realt); printf("cost time %ld Sec : %ld Msec\n", p_real_secs, (999999 - p_realt.it_value.tv_usec) / 1000); } int wakeupme = 0; //part B鬧鐘 void dealalarm(int signum) //鬧鐘處理函式 { wakeupme = 1; } int main(int argc,char **argv) { long fib = 0, microsecond; pid_t pid1, pid2; int msecond, usecond; struct timeval tv; if(argv[1][0] == '-' && argv[1][1] == 'a' && argc == 3) { printf("-----PART A-----\n"); mygettimeofday(atoi(argv[2]),fibonacci); return 0; } else if(argv[1][0] == '-' && argv[1][1] == 'b') { printf("-----PART B-----\n"); struct timeval tv; gettimeofday(&tv, NULL); struct tm *tmptime; tmptime = localtime(&tv.tv_sec); printf("now time > %d-%d-%d %d:%d:%d:%d:%d\n",tmptime->tm_year+1900,tmptime->tm_mon+1,tmptime->tm_mday,tmptime->tm_hour,tmptime->tm_min,tmptime->tm_sec,(int)tv.tv_usec/1000,(int)tv.tv_usec%1000); struct tm inputtime; int year, month, day, hour, minute, second; printf("set alarm : "); scanf("%d-%d-%d %d:%d:%d:%d:%d",&year,&month,&day,&hour, &minute,&second,&msecond,&usecond); inputtime.tm_year = year - 1900; inputtime.tm_mon = month - 1; inputtime.tm_mday = day; inputtime.tm_hour = hour; inputtime.tm_min = minute; inputtime.tm_sec = second; inputtime.tm_isdst = 0; inputtime.tm_wday = 0; inputtime.tm_yday = 0; microsecond = mktime(&inputtime) * 1000000 + msecond * 1000 + usecond; microsecond -= tv.tv_sec * 1000000 + tv.tv_usec; signal(SIGALRM,dealalarm); p_realt.it_value.tv_sec = microsecond / 1000000; p_realt.it_value.tv_usec = microsecond % 1000000; p_realt.it_interval.tv_sec = 0; p_realt.it_interval.tv_usec = 0; setitimer(ITIMER_REAL,&p_realt,NULL); while(!wakeupme); printf("wake time > %d-%d-%d %d:%d:%d:%d:%d\n",inputtime.tm_year+1900,inputtime.tm_mon+1,inputtime.tm_mday,inputtime.tm_hour,inputtime.tm_min,inputtime.tm_sec,msecond,usecond); return 0; } else if(argv[1][0] == '-' && argv[1][1] == 'c' && argc == 5) { printf("-----PART C-----\n"); //bind signal and function for parent process signal(SIGALRM,psig_real); signal(SIGVTALRM,psig_virtual); signal(SIGPROF,psig_prof); //init parent process 3 timer 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); 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) { //bind signal and function for child1 process signal(SIGALRM,c1sig_real); signal(SIGVTALRM,c1sig_virtual); signal(SIGPROF,c1sig_prof); //init child1 process 3 timer c1_realt.it_interval.tv_sec = 0; c1_realt.it_interval.tv_usec = 999999; c1_realt.it_value.tv_sec = 0; c1_realt.it_value.tv_usec = 999999; setitimer(ITIMER_REAL,&c1_realt,NULL); c1_virtt.it_interval.tv_sec = 0; c1_virtt.it_interval.tv_usec = 999999; c1_virtt.it_value.tv_sec = 0; c1_virtt.it_value.tv_usec = 999999; setitimer(ITIMER_VIRTUAL,&c1_virtt,NULL); c1_proft.it_interval.tv_sec = 0; c1_proft.it_interval.tv_usec = 999999; c1_proft.it_value.tv_sec = 0; c1_proft.it_value.tv_usec = 999999; setitimer(ITIMER_PROF,&c1_proft,NULL); //get fibonacci fib = fibonacci(atoi(argv[2])); //get child1 3 time and fibnacci printf("Child1 fib = %ld\n", fib); getitimer(ITIMER_REAL,&c1_realt); printf("Child1 Real Time = %ld Sec : %ld Msec\n", 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",c1_prof_secs + 9-c1_proft.it_value.tv_sec,(999999-c1_proft.it_value.tv_usec)/1000); exit(0); } else if((pid2=fork()) == 0) { //bind signal and function for child2 process signal(SIGALRM,c2sig_real); signal(SIGVTALRM,c2sig_virtual); signal(SIGPROF,c2sig_prof); //init child2 process 3 timer 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); //get fibonacci fib = fibonacci(atoi(argv[3])); //get child2 3 time and fibnacci printf("Child2 fib = %ld\n", fib); getitimer(ITIMER_REAL,&c2_realt); printf("Child2 Real Time = %ld Sec : %ld Msec\n",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",c2_prof_secs+9-c2_proft.it_value.tv_sec,(999999-c2_proft.it_value.tv_usec)/ 1000); exit(0); } else { //get fibonacci fib = fibonacci(atoi(argv[4])); //print parent 3 time and fibnacci printf("Parent fib = %ld\n", fib); getitimer(ITIMER_REAL,&p_realt); printf("Parent Real Time = %ld Sec : %ld Msec\n", 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", p_prof_secs + 9 - p_proft.it_value.tv_sec, (999999 - p_proft.it_value.tv_usec) / 1000); //wait child process waitpid(pid1,NULL,0); waitpid(pid2,NULL,0); } } } //parent process signal function void psig_real(int signum) { p_real_secs += 10; } void psig_virtual(int signum) { p_virtual_secs += 10; } void psig_prof(int signum) { p_prof_secs += 10; } //child1 process signal function void c1sig_real(int signum) { c1_real_secs += 10; } void c1sig_virtual(int signum) { c1_virtual_secs += 10; } void c1sig_prof(int signum) { c1_prof_secs += 10; } //child2 process signal function void c2sig_real(int signum) { c2_real_secs += 10; } void c2sig_virtual(int signum) { c2_virtual_secs += 10; } void c2sig_prof(int signum) { c2_prof_secs += 10; } //get fibonacci by n long fibonacci(unsigned int n) { if(n == 1 || n == 2) return 1; return fibonacci(n-1)+fibonacci(n-2); }