版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、 學(xué)號(hào):課 程 設(shè) 計(jì) 課程名稱操作系統(tǒng)學(xué) 院計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院專 業(yè)軟件工程專業(yè)班 級(jí)中國好學(xué)長系列姓 名小灰灰的爸爸指導(dǎo)教師劉 軍 2013?7>2014學(xué)年 第1學(xué)期目錄課程設(shè)計(jì)任務(wù)書1摘要21設(shè)計(jì)題目與要求21.1設(shè)計(jì)題目:內(nèi)核定時(shí)器21.2設(shè)計(jì)要求:通過研究內(nèi)核的時(shí)間管理算法,學(xué)習(xí)內(nèi)核源代碼;然后應(yīng)用這些知識(shí)并且使用“信號(hào)”建立一種用戶空間機(jī)制來測量一個(gè)多線程程序的執(zhí)行時(shí)間。22 總的設(shè)計(jì)思想及系統(tǒng)平臺(tái)、語言、工具22.1 設(shè)計(jì)思想:22.1.1 Linux內(nèi)核對(duì)定時(shí)器的描述22.1.2 Linux 內(nèi)核定時(shí)器42.1.3 Linux 信號(hào)signal處理機(jī)制72.1.4多線
2、程編程82.1.5內(nèi)核定時(shí)器機(jī)制的實(shí)現(xiàn)102.2 系統(tǒng)平臺(tái):132.3 編程工具:133.數(shù)據(jù)結(jié)構(gòu)與模塊說明(功能與流程圖)133.1 定時(shí)器使用:133.2 多線程程序:143.3程序流程圖:154. 源程序:155.運(yùn)行結(jié)果與運(yùn)行情況166.調(diào)試記錄:177.自我評(píng)析和總結(jié):188.參考文獻(xiàn)18評(píng)分表19課程設(shè)計(jì)任務(wù)書學(xué)生姓名:專業(yè)班級(jí):指導(dǎo)教師: 劉軍 工作單位: 計(jì)算機(jī)科學(xué)與技術(shù)學(xué)院 題目: 內(nèi)核定時(shí)器初始條件: 操作系統(tǒng):Linux 程序設(shè)計(jì)語言:C語言 3.有界緩沖區(qū)內(nèi)設(shè)有20個(gè)儲(chǔ)存單元,其初值為0,放入/取出的數(shù)據(jù)項(xiàng)按增序設(shè)定為1-20這20個(gè)整型數(shù)要求完成的主要任務(wù): (包括課
3、程設(shè)計(jì)工作量及其技術(shù)要求,以及說明書撰寫等具體要求) 1.技術(shù)要求: 通過研究內(nèi)核的時(shí)間管理算法學(xué)習(xí)內(nèi)核源代碼。然后應(yīng)用這些知識(shí)并且使用“信號(hào)”建立一種用戶空間機(jī)制來測量一個(gè)多線程程序的執(zhí)行時(shí)間。 實(shí)驗(yàn)條件要求:每人一臺(tái)Linux主機(jī)且有超級(jí)用戶權(quán)限。 2. 設(shè)計(jì)說明書內(nèi)容要求: 1設(shè)計(jì)題目與要求 2總的設(shè)計(jì)思想及系統(tǒng)平臺(tái)、語言、工具等 3數(shù)據(jù)結(jié)構(gòu)與模塊說明(功能與流程圖) 4運(yùn)行結(jié)果與運(yùn)行情況 3. 調(diào)試報(bào)告: 1調(diào)試記錄 2自我評(píng)析和總結(jié)時(shí)間安排: 序號(hào)階段內(nèi)容所需時(shí)間1消化資料、系統(tǒng)設(shè)計(jì)1天2編程、調(diào)試3天3撰寫報(bào)告1天合計(jì)5天指導(dǎo)教師簽名: 2013年12月26日系主任(或責(zé)任教師)簽
4、名: 年月日內(nèi)核定時(shí)器摘要 每個(gè)進(jìn)程包含一到多個(gè)線程。進(jìn)程也可能是整個(gè)程序或者是部分程序的動(dòng)態(tài)執(zhí)行。線程是一組指令的集合,或者是程序的特殊段,它可以在程序里獨(dú)立執(zhí)行。也可以把它理解為代碼運(yùn)行的上下文。內(nèi)核時(shí)間指明線程執(zhí)行操作系統(tǒng)代碼已經(jīng)經(jīng)過了多少個(gè)100ns的CPU時(shí)間,linux是一個(gè)具有保護(hù)模式的操作系統(tǒng)。它一直工作在i386 cpu的保護(hù)模式之下。內(nèi)存被分為兩個(gè)單元: 內(nèi)核區(qū)域和用戶區(qū)域。一般地,在使用虛擬內(nèi)存技術(shù)的多任務(wù)系統(tǒng)上,內(nèi)核和應(yīng)用有不同的地址空間,因此,在內(nèi)核和應(yīng)用之間以及在應(yīng)用與應(yīng)用之間進(jìn)行數(shù)據(jù)交換需要專門的機(jī)制來實(shí)現(xiàn),本文站在用戶空間的角度,測試一個(gè)多線程程序的程序執(zhí)行時(shí)間
5、。當(dāng)一個(gè)進(jìn)程希望獲得信號(hào)量時(shí), 如果信號(hào)量已經(jīng)被占有, 則該進(jìn)程將會(huì)被放到等待隊(duì)列上sleep直到cpu將其喚醒。相對(duì)于spinlock來說開銷太大,適用于長時(shí)間占有的lock。不可用于中斷狀態(tài),因?yàn)樗鼡碛行盘?hào)量的進(jìn)程可以sleep, 可以被搶占。1設(shè)計(jì)題目與要求1.1設(shè)計(jì)題目:內(nèi)核定時(shí)器1.2設(shè)計(jì)要求:通過研究內(nèi)核的時(shí)間管理算法,學(xué)習(xí)內(nèi)核源代碼;然后應(yīng)用這些知識(shí)并且使用“信號(hào)”建立一種用戶空間機(jī)制來測量一個(gè)多線程程序的執(zhí)行時(shí)間。2 總的設(shè)計(jì)思想及系統(tǒng)平臺(tái)、語言、工具2.1設(shè)計(jì)思想:時(shí)器:struct timer_list struct list_head list;unsigned long
6、 expires;unsigned long data;void *functionunsigned long; 各數(shù)據(jù)成員的含義如下:(1)雙向鏈表元素list:用來將多個(gè)定時(shí)器連接成一條雙向循環(huán)隊(duì)列。(2)expires:指定定時(shí)器到期的時(shí)間,這個(gè)時(shí)間被表示成自系統(tǒng)啟動(dòng)以來的時(shí)鐘滴答計(jì)數(shù)(也即時(shí)鐘節(jié)拍數(shù))。當(dāng)一個(gè)定時(shí)器的expires值小于或等于jiffies變量時(shí),我們就說這個(gè)定時(shí)器已經(jīng)超時(shí)或到期了。在初始化一個(gè)定時(shí)器后,通常把它的expires域設(shè)置成當(dāng)前expires變量的當(dāng)前值加上某個(gè)時(shí)間間隔值(以時(shí)鐘滴答次數(shù)計(jì))。(3)函數(shù)指針function:指向一個(gè)可執(zhí)行函數(shù)。當(dāng)定時(shí)器到期時(shí)
7、,內(nèi)核就執(zhí)行function所指定的函數(shù)。而data域則被內(nèi)核用作function函數(shù)的調(diào)用參數(shù)。內(nèi)核函數(shù)init_timer用來初始化一個(gè)定時(shí)器。實(shí)際上,這個(gè)初始化函數(shù)僅僅將結(jié)構(gòu)中的list成員初始化為空。如下所示(include/linux/timer.h):static inline void init_timerstruct timer_list * timertimer-list.next timer-list.prev NULL; 由于定時(shí)器通常被連接在一個(gè)雙向循環(huán)隊(duì)列中等待執(zhí)行(此時(shí)我們說定時(shí)器處于pending狀態(tài))。因此函數(shù)time_pending就可以用list成員是否為空
8、來判斷一個(gè)定時(shí)器是否處于pending狀態(tài)。如下所示(include/linux/timer.h):static inline int timer_pending const struct timer_list * timerreturn timer-list.next ! NULL; 時(shí)間比較操作在定時(shí)器應(yīng)用中經(jīng)常需要比較兩個(gè)時(shí)間值,以確定timer是否超時(shí),所以Linux內(nèi)核在timer.h頭文件中定義了4個(gè)時(shí)間關(guān)系比較操作宏。這里我們說時(shí)刻a在時(shí)刻b之后,就意味著時(shí)間值ab。Linux強(qiáng)烈推薦用戶使用它所定義的下列4個(gè)時(shí)間比較操作宏(include/linux/timer.h):#def
9、ine time_aftera,b longb - longa 0#define time_beforea,b time_afterb,a #define time_after_eqa,b longa - longb 0#define time_before_eqa,b time_after_eqb,a2.1.2Linux 內(nèi)核定時(shí)器 定時(shí)器是管理內(nèi)核時(shí)間的基礎(chǔ),用來計(jì)算流逝的時(shí)間,它以某種頻率(節(jié)拍率)自行觸發(fā)時(shí)鐘中斷,當(dāng)時(shí)鐘中斷發(fā)生時(shí),內(nèi)核就通過一種特殊中斷處理程序?qū)ζ溥M(jìn)行處理。但是原來的實(shí)現(xiàn)只能是time_t mytime形式的,經(jīng)過簡單的localtimemytime和ctime&am
10、p;mytime處理.精度是不夠的,為了返回高精度的時(shí)間,這里使用了gettimeofday函數(shù)。這個(gè)syscall用來供用戶獲取timeval格式的當(dāng)前時(shí)間信息(精確度為微秒級(jí)),以及系統(tǒng)的當(dāng)前時(shí)區(qū)信息(timezone)。結(jié)構(gòu)類型timeval的指針參數(shù)tv指向接受時(shí)間信息的用戶空間緩沖區(qū),參數(shù)tz是一個(gè)timezone結(jié)構(gòu)類型的指針,指向接收時(shí)區(qū)信息的用戶空間緩沖區(qū)。這兩個(gè)參數(shù)均為輸出參數(shù),返回值0表示成功,返回負(fù)值表示出錯(cuò)。函數(shù)sys_gettimeofday的源碼如下(kernel/time.c): asmlinkage long sys_gettimeofdaystruct tim
11、eval *tv, struct timezone *tz if tv struct timeval ktv; do_gettimeofday&ktv; if copy_to_usertv, &ktv, sizeofktv return -EFAULT; if tz if copy_to_usertz, &sys_tz, sizeofsys_tz return -EFAULT; return 0; 顯然,函數(shù)的實(shí)現(xiàn)主要分成兩個(gè)大的方面: (1)如果tv指針有效,則說明用戶要以timeval格式來檢索系統(tǒng)當(dāng)前時(shí)間。為此,先調(diào)用do_gettimeofday函數(shù)來檢索系統(tǒng)當(dāng)
12、前時(shí)間并保存到局部變量ktv中。然后再調(diào)用copy_to_user()宏將保存在內(nèi)核空間中的當(dāng)前時(shí)間信息拷貝到由參數(shù)指針tv所指向的用戶空間緩沖區(qū)中。 (2)如果tz指針有效,則說明用戶要檢索當(dāng)前時(shí)區(qū)信息,因此調(diào)用copy_to_user宏將全局變量sys_tz中的時(shí)區(qū)信息拷貝到參數(shù)指針tz所指向的用戶空間緩沖區(qū)中。 (3)最后,返回0表示成功。 函數(shù)do_gettimeofday的源碼如下(arch/i386/kernel/time.c): /* * This version of gettimeofday has microsecond resolution * and better th
13、an microsecond precision on fast x86 machines with TSC*/ void do_gettimeofdaystruct timeval *tv unsigned long flags; unsigned long usec, sec; read_lock_irqsave&xtime_lock, flags; usec do_gettimeoffset; unsigned long lost jiffies - wall_jiffies; if lost usec + lost * 1000000 / HZ; sec xtime.tv_se
14、c; usec + xtime.tv_usec; read_unlock_irqrestore&xtime_lock, flags; while usec 1000000 usec - 1000000; sec+; tv-tv_sec sec; tv-tv_usec usec; 該函數(shù)的完成實(shí)際的當(dāng)前時(shí)間檢索工作。由于gettimeofday系統(tǒng)調(diào)用要求時(shí)間精度要達(dá)到微秒級(jí),因此do_gettimeofday函數(shù)不能簡單地返回xtime中的值即可,而必須精確地確定自從時(shí)鐘驅(qū)動(dòng)的Bottom Half上一次更新xtime的那個(gè)時(shí)刻到do_gettimeofday函數(shù)的當(dāng)前執(zhí)行時(shí)刻之間的具
15、體時(shí)間間隔長度,以便精確地修正xtime的值.假定被do_gettimeofday用來修正xtime的時(shí)間間隔為fixed_usec,而從wall_jiffies到j(luò)iffies之間的時(shí)間間隔是lost_usec,而從jiffies到do_gettimeofday函數(shù)的執(zhí)行時(shí)刻的時(shí)間間隔是offset_usec。則下列三個(gè)等式成立: fixed_usec=(lost_usec+offset_usec) lost_usec=(jiffies-wall_jiffies)*TICK_SIZE=(jiffies-wall_jiffies)*(1000000/HZ) 由于全局變量last_tsc_low
16、表示上一次時(shí)鐘中斷服務(wù)函數(shù)timer_interrupt執(zhí)行時(shí)刻的CPU TSC寄存器的值,因此我們可以用X86 CPU的TSC寄存器來計(jì)算offset_usec的值。也即: offset_usecdelay_at_last_interrupt+(current_tsc_low-last_tsc_low)*fast_gettimeoffset_quotient 其中,delay_at_last_interrupt是從上一次發(fā)生時(shí)鐘中斷到timer_interrupt服務(wù)函數(shù)真正執(zhí)行時(shí)刻之間的時(shí)間延遲間隔。每一次timer_interrupt被執(zhí)行時(shí)都會(huì)計(jì)算這一間隔,并利用TSC的當(dāng)前值更新la
17、st_tsc_low變量(可以參見7.4節(jié))。假定current_tsc_low是do_gettimeofday函數(shù)執(zhí)行時(shí)刻TSC的當(dāng)前值,全局變量fast_gettimeoffset_quotient則表示TSC寄存器每增加1所代表的時(shí)間間隔值,它是由time_init函數(shù)所計(jì)算的。 根據(jù)上述原理分析,do_gettimeofday函數(shù)的執(zhí)行步驟如下: (1)調(diào)用函數(shù)do_gettimeoffset計(jì)算從上一次時(shí)鐘中斷發(fā)生到執(zhí)行do_gettimeofday函數(shù)的當(dāng)前時(shí)刻之間的時(shí)間間隔offset_usec。 (2)通過wall_jiffies和jiffies計(jì)算lost_usec的值。 (
18、3)然后,令secxtime.tv_sec,usecxtime.tv_usec+lost_usec+offset_usec。顯然,sec表示系統(tǒng)當(dāng)前時(shí)間在秒數(shù)量級(jí)上的值,而usec表示系統(tǒng)當(dāng)前時(shí)間在微秒量級(jí)上的值。 (4)用一個(gè)while循環(huán)來判斷usec是否已經(jīng)溢出而超過106us=1秒。如果溢出,則將usec減去106us并相應(yīng)地將sec增加1,直到usec不溢出為止。 (5)最后,用sec和usec分別更新參數(shù)指針?biāo)赶虻膖imeval結(jié)構(gòu)變量。至此,整個(gè)查詢過程結(jié)束。函數(shù)do_gettimeoffset根據(jù)CPU是否配置有TSC寄存器這一條件分別有不同的實(shí)現(xiàn)。其定義如下(arch/i3
19、86/kernel/time.c): #ifndef CONFIG_X86_TSC static unsigned long do_slow_gettimeoffsetvoid static unsigned long *do_gettimeoffsetvoid do_slow_gettimeoffset; #else #define do_gettimeoffset do_fast_gettimeoffset #endif 顯然,在配置有TSC寄存器的i386平臺(tái)上,do_gettimeoffset()函數(shù)實(shí)際上就是do_fast_gettimeoffset函數(shù)。它通過TSC寄存器來計(jì)算do
20、_fast_gettimeoffset函數(shù)被執(zhí)行的時(shí)刻到上一次時(shí)鐘中斷發(fā)生時(shí)的時(shí)間間隔值。其源碼如下(arch/i386/kernel/time.c): static inline unsigned long do_fast_gettimeoffsetvoid register unsigned long eax, edx; /* Read the Time Stamp Counter */ rdtsceax,edx; /* relative to previous jiffy 32 bits is enough */ eax - last_tsc_low; /* tsc_low delta
21、*/ /* * Time offset tsc_low delta * fast_gettimeoffset_quotient * tsc_low delta * usecs_per_clock * tsc_low delta * usecs_per_jiffy / clocks_per_jiffy * * Using a mull instead of a divl saves up to 31 clock cycles * in the critical path*/ _asm_"mull %2" :"a" eax, "d" ed
22、x :"rm" fast_gettimeoffset_quotient, "0" eax; /* our adjusted time offset in microseconds */ return delay_at_last_interrupt + edx; 對(duì)該函數(shù)的注釋如下: (1)先調(diào)用rdtsc函數(shù)讀取當(dāng)前時(shí)刻TSC寄存器的值,并將其高32位保存在edx局部變量中,低32位保存在局部變量eax中。 (2)讓局部變量eax=tsc_low=eax-last_tsc_low;也即計(jì)算當(dāng)前時(shí)刻的TSC值與上一次時(shí)鐘中斷服務(wù)函數(shù)timer_interr
23、upt執(zhí)行時(shí)的TSC值之間的差值。 (3)顯然,從上一次timer_interrupt到當(dāng)前時(shí)刻的時(shí)間間隔就是(tsc_low*fast_gettimeoffset_quotient)。因此用一條mul指令來計(jì)算這個(gè)乘法表達(dá)式的值。 (4)返回值delay_at_last_interrupt+(tsc_low*fast_gettimeoffset_quotient)就是從上一次時(shí)鐘中斷發(fā)生時(shí)到當(dāng)前時(shí)刻之間的時(shí)間偏移間隔值。2.1.3Linux 信號(hào)signal處理機(jī)制 信號(hào)signal機(jī)制是進(jìn)程之間相互傳遞消息的一種方法,全稱為軟中斷信號(hào)。系統(tǒng)調(diào)用signal用來設(shè)定某個(gè)信號(hào)的處理方法,其調(diào)用
24、聲明的格式如下: void *signalint signum, void *handlerintint; 成功則返回該信號(hào)以前的處理配置,出錯(cuò)則返回SIG_ERR。在使用該調(diào)用的進(jìn)程中加入以下頭文件:幾個(gè)常見信號(hào):SIGINT: 當(dāng)用戶按某些終端鍵時(shí), 引發(fā)終端產(chǎn)生的信號(hào). 如Ctrl+C鍵, 這將產(chǎn)生中斷信號(hào)SIGINT,它將停止一個(gè)已失去控制的程序。SIGSEGV: 由硬件異常除數(shù)為0, 無效的內(nèi)存引用等等產(chǎn)生的信號(hào)。這些條件通常由硬件檢測到, 并將其通知內(nèi)核,然后內(nèi)核為該條件發(fā)生時(shí)正在運(yùn)行的進(jìn)程產(chǎn)生該信號(hào)。SIGURG: 在網(wǎng)絡(luò)連接上傳來帶外數(shù)據(jù)時(shí)產(chǎn)生。SIGPIPE: 在管道的讀進(jìn)程
25、已終止后, 一個(gè)進(jìn)程寫此管道時(shí)產(chǎn)生,當(dāng)類型為SOCK_STREAM的socket已不再連接時(shí), 進(jìn)程寫到該socket也產(chǎn)生此信號(hào)。SIGALRM: 進(jìn)程所設(shè)置的鬧鐘時(shí)鐘超時(shí)的時(shí)候產(chǎn)生。SIGABRT: 進(jìn)程調(diào)用abort函數(shù)時(shí)產(chǎn)生此信號(hào), 進(jìn)程異常終止。SIGCHLD: 在一個(gè)進(jìn)程終止或停止時(shí), 它將把該信號(hào)發(fā)送給其父進(jìn)程。 按系統(tǒng)默認(rèn), 將忽略此信號(hào),如果父進(jìn)程希望被告知其子進(jìn)程的這種狀態(tài)改變, 則應(yīng)該捕捉此信號(hào)。通常是用wait系列函數(shù)捕捉, 如果不wait的話, 子進(jìn)程將成為一個(gè)僵尸進(jìn)程。SIGIO: 此信號(hào)指示一個(gè)異步I/O事件。SIGSYS: 該信號(hào)指示一個(gè)無效的系統(tǒng)調(diào)用。SIGT
26、STP: 交互式停止信號(hào). Ctrl+Z, 按下時(shí), 終端將產(chǎn)生此信號(hào), 進(jìn)程被掛起。 多線程是計(jì)算機(jī)同時(shí)運(yùn)行多個(gè)執(zhí)行線程的能力(這些線程可以是同一程序的組成部分,或者也可以是完全不同的程序)。Linux系統(tǒng)下的多線程遵循POSIX線程接口,稱為pthread。編寫Linux下的多線程程序,需要使用頭文件pthread.h,連接時(shí)需要使用庫libpthread.a。而Linux下pthread的實(shí)現(xiàn)是通過系統(tǒng)調(diào)用clone()來實(shí)現(xiàn)的。clone()是Linux所特有的系統(tǒng)調(diào)用,它的使用方式類似fork。下面展示多線程程序部分050119.c。/* 050119.c */#include #i
27、nclude void threadvoidint i;fori0;i3;i+printf"This is a pthread.n" int pthread voidpthread_t id;int i,ret;retpthread_create&id,NULL,void * thread,NULL;ifret!0printf "Create pthread error!n"exit 1;fori0;i3;i+printf"This is the main process.n"pthread_joinid,NULL;retur
28、n 0;我們編譯此程序:運(yùn)行050119.out,我們得到如下結(jié)果:This is the main process.This is a pthread.This is the main process.This is the main process.This is a pthread.This is a pthread.再次運(yùn)行,我們可能得到如下結(jié)果:This is a pthread.This is the main process.This is a pthread.This is the main process.This is a pthread.This is the main
29、process.前后兩次結(jié)果不一樣,這是兩個(gè)線程爭奪CPU資源的結(jié)果。上面的示例中,我們使用到了兩個(gè)函數(shù),pthread_create和pthread_join,并聲明了一個(gè)pthread_t型的變量。pthread_t在頭文件/usr/include/bits/pthreadtypes.h中定義:typedef unsigned long int pthread_t;它是一個(gè)線程的標(biāo)識(shí)符。函數(shù)pthread_create用來創(chuàng)建一個(gè)線程,它的原型為:extern int pthread_create _P pthread_t *_thread, _const pthread_attr_t *
30、_attr,void *_start_routine void *, void *_arg;第一個(gè)參數(shù)為指向線程標(biāo)識(shí)符的指針,第二個(gè)參數(shù)用來設(shè)置線程屬性,第三個(gè)參數(shù)是線程運(yùn)行函數(shù)的起始地址,最后一個(gè)參數(shù)是運(yùn)行函數(shù)的參數(shù)。這里,我們的函 數(shù)thread不需要參數(shù),所以最后一個(gè)參數(shù)設(shè)為空指針。第二個(gè)參數(shù)我們也設(shè)為空指針,這樣將生成默認(rèn)屬性的線程。對(duì)線程屬性的設(shè)定和修改我們將在下一節(jié) 闡述。當(dāng)創(chuàng)建線程成功時(shí),函數(shù)返回0,若不為0則說明創(chuàng)建線程失敗,常見的錯(cuò)誤返回代碼為EAGAIN和EINVAL。前者表示系統(tǒng)限制創(chuàng)建新的線程,例如線程數(shù)目過多了;后者表示第二個(gè)參數(shù)代表的線程屬性值非法。創(chuàng)建線程成功后,
31、新創(chuàng)建的線程則運(yùn)行參數(shù)三和參數(shù)四確定的函數(shù),原來的線程則繼續(xù)運(yùn)行下一行代碼。函數(shù)pthread_join用來等待一個(gè)線程的結(jié)束。函數(shù)原型為:extern int pthread_join _P pthread_t _th, void *_thread_return;第一個(gè)參數(shù)為被等待的線程標(biāo)識(shí)符,第二個(gè)參數(shù)為一個(gè)用戶定義的指針,它可以用來存儲(chǔ)被等待線程的返回值。這個(gè)函數(shù)是一個(gè)線程阻塞的函數(shù),調(diào)用它的函數(shù)將 一直等待到被等待的線程結(jié)束為止,當(dāng)函數(shù)返回時(shí),被等待線程的資源被收回。一個(gè)線程的結(jié)束有兩種途徑,一種是象我們上面的例子一樣,函數(shù)結(jié)束了,調(diào)用它的 線程也就結(jié)束了;另一種方式是通過函數(shù)pthr
32、ead_exit來實(shí)現(xiàn)。它的函數(shù)原型為:extern void pthread_exit _P void *_retval _attribute_ _noreturn_;唯一的參數(shù)是函數(shù)的返回代碼,只要pthread_join中的第二個(gè)參數(shù)thread_return不是NULL,這個(gè)值將被傳遞給 thread_return。最后要說明的是,一個(gè)線程不能被多個(gè)線程等待,否則第一個(gè)接收到信號(hào)的線程成功返回,其余調(diào)用pthread_join的線 程則返回錯(cuò)誤代碼ESRCH。2.1.5.1動(dòng)態(tài)定時(shí)器機(jī)制的初始化函數(shù)init_timervecs實(shí)現(xiàn)對(duì)動(dòng)態(tài)定時(shí)器機(jī)制的初始化。該函數(shù)僅被sched_init
33、初始化例程所調(diào)用。動(dòng)態(tài)定時(shí)器機(jī)制初始化過程的主要任務(wù)就是將tv1、tv2、tv5這5個(gè)結(jié)構(gòu)變量中的定時(shí)器向量指針數(shù)組vec初始化為NULL。如下所示(kernel/timer.c):void init_timervecs voidint i; for i 0; i TVN_SIZE; i+ INIT_LIST_HEADtv5.vec + i;INIT_LIST_HEADtv4.vec + i;INIT_LIST_HEADtv3.vec + i;INIT_LIST_HEADtv2.vec + i;for i 0; i TVR_SIZE; i+INIT_LIST_HEADtv1.vec + i;
34、上述函數(shù)中的宏TVN_SIZE是指timer_vec結(jié)構(gòu)類型中的定時(shí)器向量指針數(shù)組vec的大小,值為64。宏TVR_SIZE是指timer_vec_root結(jié)構(gòu)類型中的定時(shí)器向量數(shù)組vec的大小,值為256。2.1.5.2將一個(gè)定時(shí)器插入到鏈表中 函數(shù)add_timer用來將參數(shù)timer指針?biāo)赶虻亩〞r(shí)器插入到一個(gè)合適的定時(shí)器鏈表中。它首先調(diào)用timer_pending函數(shù)判斷所指定的定時(shí)器是否已經(jīng)位于在某個(gè)定時(shí)器向量中等待執(zhí)行。如果是,則不進(jìn)行任何操作,只是打印一條內(nèi)核告警信息就返回了;如果不是,則調(diào)用internal_add_timer函數(shù)完成實(shí)際的插入操作。其源碼如下(kernel/t
35、imer.c):void add_timerstruct timer_list *timerunsigned long flags; spin_lock_irqsave&timerlist_lock, flags;if timer_pendingtimergoto bug;internal_add_timertimer;spin_unlock_irqrestore&timerlist_lock, flags;return;bug:spin_unlock_irqrestore&timerlist_lock, flags;printk"bug: kernel ti
36、mer added twice at %p.n",_builtin_return_address0; 函數(shù)internal_add_timer用于將一個(gè)不處于任何定時(shí)器向量中的定時(shí)器插入到它應(yīng)該所處的定時(shí)器向量中去(根據(jù)定時(shí)器的expires值來決定)。如下所示(kernel/timer.c):static inline void internal_add_timerstruct timer_list *timer/* must be cli-ed when calling this*/unsigned long expires timer-expires;unsigned long
37、 idx expires - timer_jiffies;struct list_head * vec; if idx TVR_SIZE int i expires & TVR_MASK;vec tv1.vec + i; else if idx 1 TVR_BITS + TVN_BITS int i expires TVR_BITS & TVN_MASK;vec tv2.vec + i; else if idx 1 TVR_BITS + 2 * TVN_BITS int i expires TVR_BITS + TVN_BITS & TVN_MASK;vec tv3.v
38、ec + i; else if idx 1 TVR_BITS + 3 * TVN_BITS int i expires TVR_BITS + 2 * TVN_BITS & TVN_MASK;vec tv4.vec + i; else if signed long idx 0 /* can happen if you add a timer with expires jiffies,* or you set a timer to go off in the past*/vec tv1.vec + tv1.index; else if idx 0xffffffffUL int i expi
39、res TVR_BITS + 3 * TVN_BITS & TVN_MASK;vec tv5.vec + i; else /* Can only get here on architectures with 64-bit jiffies */ INIT_LIST_HEAD&timer-list;return;/* Timers are FIFO!*/list_add&timer-list, vec-prev; 對(duì)該函數(shù)的注釋如下:(1)首先,計(jì)算定時(shí)器的expires值與timer_jiffies的插值(注意!這里應(yīng)該使用動(dòng)態(tài)定時(shí)器自己的時(shí)間基準(zhǔn)),這個(gè)差值就表示這個(gè)定
40、時(shí)器相對(duì)于上一次運(yùn)行定時(shí)器機(jī)制的那個(gè)時(shí)刻還需要多長時(shí)間間隔才到期。局部變量idx保存這個(gè)差值。(2)根據(jù)idx的值確定這個(gè)定時(shí)器應(yīng)被插入到哪一個(gè)定時(shí)器向量中。其具體的確定方法我們?cè)?.6.2節(jié)已經(jīng)說過了,這里不再詳述。最后,定時(shí)器向量的頭部指針vec表示這個(gè)定時(shí)器應(yīng)該所處的定時(shí)器向量鏈表頭部。(3)最后,調(diào)用list_add函數(shù)將定時(shí)器插入到vec指針?biāo)赶虻亩〞r(shí)器隊(duì)列的尾部。2.1.5.3修改一個(gè)定時(shí)器的expires值當(dāng)一個(gè)定時(shí)器已經(jīng)被插入到內(nèi)核動(dòng)態(tài)定時(shí)器鏈表中后,我們還可以修改該定時(shí)器的expires值。函數(shù)mod_timer實(shí)現(xiàn)這一點(diǎn)。如下所示(kernel/timer.c):int
41、mod_timerstruct timer_list *timer, unsigned long expires int ret;unsigned long flags; spin_lock_irqsave&timerlist_lock, flags;timer-expires expires;ret detach_timertimer;internal_add_timertimer;spin_unlock_irqrestore&timerlist_lock, flags;return ret; 該函數(shù)首先根據(jù)參數(shù)expires值更新定時(shí)器的expires成員。然后調(diào)用deta
42、ch_timer函數(shù)將該定時(shí)器從它原來所屬的鏈表中刪除。最后調(diào)用internal_add_timer函數(shù)將該定時(shí)器根據(jù)它新的expires值重新插入到相應(yīng)的鏈表中。函數(shù)detach_timer首先調(diào)用timer_pending來判斷指定的定時(shí)器是否已經(jīng)處于某個(gè)鏈表中,如果定時(shí)器原來就不處于任何鏈表中,則detach_timer函數(shù)什么也不做,直接返回0值,表示失敗。否則,就調(diào)用list_del函數(shù)將定時(shí)器從它原來所處的鏈表中摘除。如下所示(kernel/timer.c):static inline int detach_timer struct timer_list *timerif !tim
43、er_pendingtimerreturn 0;list_del&timer-list;return 1; 2.2.系統(tǒng)平臺(tái):一臺(tái)Linux主機(jī)且有超級(jí)用戶權(quán)限2.3編程工具:VI編輯器,Gedit編輯器3.數(shù)據(jù)結(jié)構(gòu)與模塊說明(功能與流程圖)3.1.定時(shí)器使用:int gettimeofdaystruct timeval *tv,struct timezone *tz; strut timevallong tv_sec;/*秒數(shù)*/ long tv_usec; /*微秒數(shù)*/ ;這個(gè)syscall用來供用戶獲取timeval格式的當(dāng)前時(shí)間信息(精確度為微秒級(jí)),以及系統(tǒng)的當(dāng)前時(shí)區(qū)信息(
44、timezone)。結(jié)構(gòu)類型timeval的指針參數(shù)tv指向接受時(shí)間信息的用戶空間緩沖區(qū),參數(shù)tz是一個(gè)timezone結(jié)構(gòu)類型的指針,指向接收時(shí)區(qū)信息的用戶空間緩沖區(qū)。這兩個(gè)參數(shù)均為輸出參數(shù),返回值0表示成功,返回負(fù)值表示出錯(cuò)。實(shí)現(xiàn)過程如下:main struct timeval tpstart,tpend; /*申請(qǐng)struct timeval的變量,tv_sec返回的是秒數(shù),tv_usec返回的是微秒數(shù)*/float timeuse; gettimeofday&tpstart,NULL; pthread; gettimeofday&tpend,NULL; timeuse1
45、000000*tpend.tv_sec-tpstart.tv_sec+ tpend.tv_usec-tpstart.tv_usec; timeuse/1000000; printf"Used Time:%f secn",timeuse; exit0; 3.2 多線程程序:進(jìn)行多線程程序設(shè)計(jì)時(shí),我們使用到了兩個(gè)函數(shù),pthread_create和pthread_join,并聲明了一個(gè)pthread_t型的變量。pthread_t在頭文件/usr/include/bits/pthreadtypes.h中定義,它是一個(gè)線程的標(biāo)識(shí)符。函數(shù)pthread_create用來創(chuàng)建一個(gè)線程
46、,函數(shù)pthread_join用來等待一個(gè)線程的結(jié)束。實(shí)現(xiàn)過程如下:int pthread_create&id,NULL,void * thread,NULL;pthread_joinid,NULL;void threadvoidint i;fori0;i3;i+printf"This is a pthread.n"int pthreadvoidpthread_t id;/* 聲明了一個(gè)pthread_t型的變量*/int i,ret;retpthread_create&id,NULL,void * thread,NULL;ifret!0printf&quo
47、t;Create pthread error!n"exit1;fori0;i3;i+printf"This is the main process.n"pthread_joinid,NULL;return0;3.3程序流程圖:4. 源程序: #include #include #include int gettimeofdaystruct timeval *tv,struct timezone *tz; int pthread_create&id,NULL,void * thread,NULL; /pthread_joinid,NULL; strut ti
48、mevallong tv_sec;/*秒數(shù)*/ long tv_usec; /*微秒數(shù)*/ ;void threadvoidint i;fori0;i3;i+printf"This is a pthread.n"int pthreadvoidpthread_t id;/* 聲明了一個(gè)pthread_t型的變量*/int i,ret;retpthread_create&id,NULL,void * thread,NULL;ifret!0printf"Create pthread error!n"exit1;fori0;i3;i+printf"This is the main process.n"pthread_joinid,NULL;return0;main struct timeval tpstart,tpend; /*申請(qǐng)struct timeval的變量,tv_sec返回的是秒數(shù),tv_usec返回的是微秒數(shù)*/float timeuse; gettimeofday&tpstart,NULL; pthread; gettimeofday&tpend,NULL; timeuse1000000*tpend.tv_sec-tpstar
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025擔(dān)保旅游合同書
- 2025貨物保險(xiǎn)合同范文
- 二零二五年度幼兒園園長任期幼兒身心健康保障合同3篇
- 2025年度農(nóng)村宅基地房買賣合同(農(nóng)村旅游特色小鎮(zhèn)開發(fā))
- 二零二五年度農(nóng)村土地承包權(quán)土地經(jīng)營權(quán)流轉(zhuǎn)信息化建設(shè)合同
- 二零二五年度城市民宿租賃規(guī)范合同關(guān)于房屋出租3篇
- 二零二五幼兒入園早教托班全日制服務(wù)協(xié)議樣本3篇
- 二零二五年度漁業(yè)養(yǎng)殖市場調(diào)研與養(yǎng)魚合同3篇
- 二零二五年度新能源汽車核心零部件供貨協(xié)議模板3篇
- 2025年度園林景觀設(shè)計(jì)樹木補(bǔ)償合同3篇
- Unit 4 Plants around us Part A(說課稿)-2024-2025學(xué)年人教PEP版(2024)英語三年級(jí)上冊(cè)
- “小城鎮(zhèn)建設(shè)”論文(六篇)
- 安徽省蕪湖市2023-2024學(xué)年高一上學(xué)期期末考試 生物 含解析
- 設(shè)備維護(hù)保養(yǎng)培訓(xùn)
- 三管三必須-新安法宣貫課件
- 農(nóng)戶種地合作協(xié)議書范本模板
- 住院病人身體約束護(hù)理
- 公共機(jī)構(gòu)能耗定額 第3部分:教育機(jī)構(gòu)DB41-T 1960.3-2021
- “雙減”初中九年級(jí)英語課時(shí)作業(yè)設(shè)計(jì)案例
- 廣東省潮州市暨實(shí)高級(jí)中學(xué)2024-2025學(xué)年高二上學(xué)期9月月考語文試題
- GB/T 44415-2024基于全球衛(wèi)星導(dǎo)航的機(jī)動(dòng)車制動(dòng)性能路試檢驗(yàn)要求和方法
評(píng)論
0/150
提交評(píng)論