Linux程序設(shè)計上機指導(dǎo)書3:Linux進程控制(共13頁)_第1頁
Linux程序設(shè)計上機指導(dǎo)書3:Linux進程控制(共13頁)_第2頁
Linux程序設(shè)計上機指導(dǎo)書3:Linux進程控制(共13頁)_第3頁
Linux程序設(shè)計上機指導(dǎo)書3:Linux進程控制(共13頁)_第4頁
Linux程序設(shè)計上機指導(dǎo)書3:Linux進程控制(共13頁)_第5頁
已閱讀5頁,還剩8頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、精選優(yōu)質(zhì)文檔-傾情為你奉上上機三:Linux進程控制 1.目的(1)掌握系統(tǒng)調(diào)用fork(),exex(),exit()等實現(xiàn)進程創(chuàng)建;(2)掌握進程的終止方式(return、exit、_exit、abort);(3)掌握僵尸進程的產(chǎn)生和避免,以及wait,waitpid的使用;(4)了解守護進程的創(chuàng)建。2.內(nèi)容主要上機分析代碼文件。systemtest.c6-3.c6-4.c 6-8.c 6-9.c其他略。3.步驟1)Linux進程的創(chuàng)建創(chuàng)建進程可以采用幾種方式??梢詧?zhí)行一個程序(這會導(dǎo)致新進程的創(chuàng)建),也可以在程序內(nèi)調(diào)用一個 fork 或 exec來創(chuàng)建新進程。fork 調(diào)用會導(dǎo)致創(chuàng)建一個

2、子進程,而 exec 調(diào)用則會用新程序代替當前進程上下文。exec系列函數(shù)并不創(chuàng)建新進程,調(diào)用exec前后的進程ID是相同的。exec系列函數(shù)如下。#include int execv(const char *path,char* const argv);int execve(const char *path, char* const argv,char* const envp);int execvp(const char *file,char* const argv);int execl(const char *path,const char *arg,.);int execle(const

3、 char *path,const char *arg,.);int execlp(const char *file,const char *arg,.);exec函數(shù)的主要工作是清除父進程的可執(zhí)行代碼映像,用新程序的代碼覆蓋調(diào)用 exec的進程代碼。如果exec執(zhí)行成功,進程將從新程序的main函數(shù)入口開始執(zhí)行。調(diào)用exec后,除進程ID保持不變外,還有下列進程屬性也保持不變。(1)進程的父進程ID。(2)實際用戶ID和實際用戶組ID。(3)進程組ID、會話ID和控制終端。(4)定時器的剩余時間。(5)當前工作目錄及根目錄。(6)文件創(chuàng)建掩碼UMASK。(7)進程的信號掩碼。與exec系統(tǒng)調(diào)

4、用不同,system將外部可執(zhí)行程序加載執(zhí)行完畢后繼續(xù)返回調(diào)用進程。system的返回值就是被加載的程序的返回值。/* systemtest.c for test System. 調(diào)用system創(chuàng)建進程*/#include #include void main() /調(diào)用system執(zhí)行“l(fā)s -l”,并輸出system的返回值 printf(system return code=%dn,system(ls -l); return 0;【例6.3】 設(shè)計一個程序,用fork函數(shù)創(chuàng)建一個子進程,在子進程中,要求顯示子進程號與父進程號,然后顯示當前目錄下的文件信息,在父進程中同樣顯示子進程號與父

5、進程號。/*6-3.c 將一個進程分為兩個一樣的進程,打印出進程的相關(guān)信息 */#include /*文件預(yù)處理,包含標準輸入輸出庫*/#include /*文件預(yù)處理,包含system、exit等函數(shù)庫*/#include /*文件預(yù)處理,包含fork、getpid、getppid函數(shù)庫*/#include /*文件預(yù)處理,包含fork函數(shù)庫*/int main () /*C程序的主函數(shù),開始入口*/ pid_t result; result=fork(); /*調(diào)用fork函數(shù),返回值存在變量result中*/ int newret; if(result=-1) /*通過result的值來

6、判斷fork函數(shù)的返回情況,這兒先進行出錯處理*/ perror(創(chuàng)建子進程失敗); exit(0); else if (result=0)/*返回值為0代表子進程*/ printf(返回值是:%d,說明這是子進程!n此進程的進程號(PID)是:%dn此進程的父進程號(PPID)是:%dn,result,getpid(),getppid(); execl(“/bin/ls”,”ls”,”-l”,0);/*調(diào)用ls程序,顯示當前目錄下的文件信息*/ else /*返回值大于0代表父進程*/ sleep(10); printf(返回值是:%d,說明這是父進程!n此進程的進程號(PID)是:%dn此

7、進程的父進程號(PPID)是:%dn,result,getpid(),getppid(); 【步驟1】 設(shè)計編輯源程序代碼。rootlocalhost root#vi 6-3.c【步驟2】用gcc編譯程序。rootlocalhost root#gcc 6-3.c o 6-3 【步驟3】運行程序。 編譯成功后,執(zhí)行6-3,此時系統(tǒng)會出現(xiàn)運行結(jié)果,根據(jù)result的值,先顯示Linux系統(tǒng)分配給子進程的進程號(PID)和父進程號(PPID),接著運行l(wèi)s程序,顯示當前目錄下的文件信息。再等待10秒鐘后,顯示父進程的進程號(PID)和父進程號(PPID)。 【步驟4】在6-3.c代碼中改變:exec

8、l(“/bin/ls”,”ls”,”-l”,0);/*調(diào)用ls程序,顯示當前目錄下的文件信息*/替換為:printf(執(zhí)行前的進程號(PID)是:%dn,getpid(); /*顯示輸出進程號*/printf(執(zhí)行前的父進程號(PPID)是:%dn,getppid();/*顯示輸出父進程號*/execv(“6-1”, NULL);/*調(diào)用6-1程序 */執(zhí)行后觀察進程的PID和PPID是否有改變。2)Linux進程的終止 (1) 正常終止:(a) 在main函數(shù)內(nèi)執(zhí)行return語句,這等效于調(diào)用exit。(b) 調(diào)用exit函數(shù)。此函數(shù)由ANSIC定義,其操作包括調(diào)用各終止處理程序,然后關(guān)閉

9、所有標準I/O流等。(c) 調(diào)用_exit系統(tǒng)調(diào)用函數(shù),此函數(shù)由exit調(diào)用。(2) 異常終止:(a) 調(diào)用abort 。(b) 由一個信號終止。exit, _exit, _Exit 都是進程終止函數(shù)。abort產(chǎn)生 SIGABRT 信號。非正常退出,即在程序碰到災(zāi)難性錯誤時強制退出。由于是非正常退出,因此不會做其它任何操作。return與exit的區(qū)別在進程操作中exit是結(jié)束當前進程或程序并把控制權(quán)返回給調(diào)用該程序或者進程的進程即父進程并告訴父進程該當前進程的運行狀態(tài),而return是從當前函數(shù)返回,如果是在main函數(shù)中,main函數(shù)結(jié)束時隱式地調(diào)用exit函數(shù),自然也就結(jié)束了當前進程。

10、return是語言級別的,它表示了調(diào)用堆棧的返回;而exit是系統(tǒng)調(diào)用級別的,它表示了一個進程的結(jié)束。exit函數(shù)是退出應(yīng)用程序,并將應(yīng)用程序的一個狀態(tài)返回給OS,這個狀態(tài)標識了應(yīng)用程序的一些運行信息。在main函數(shù)里面return(0)和exit(0)是一樣的,子函數(shù)用return返回;而子進程用exit退出,調(diào)用exit時要調(diào)用一段終止處理程序,然后關(guān)閉所有I/O流。/*6-4.c程序:用exit和_exit函數(shù)終止進程的區(qū)別*/ #include/*文件預(yù)處理,包含標準輸入輸出庫*/#include/*文件預(yù)處理,包含exit函數(shù)庫*/#include /*文件預(yù)處理,包含fork、ex

11、it函數(shù)庫*/#include /*文件預(yù)處理,提供pid_t的定義*/int main () /*C程序的主函數(shù),開始入口*/ pid_t result;result=fork(); /*調(diào)用fork函數(shù),返回值存在變量result中*/if(result=-1) /*通過result的值來判斷fork函數(shù)的返回情況,這兒先進行出錯處理*/perror(創(chuàng)建子進程失敗);exit(0);else if (result=0) /*返回值為0代表子進程*/printf(測試終止進程的_exit函數(shù)!n);printf(目前為子進程,這一行我們用緩存!);_exit(0);else /*返回值大于

12、0代表父進程*/printf(測試終止進程的exit函數(shù)!n);printf(目前為父進程,這一行我們用緩存!);exit(0);3)Linux的僵尸進程(wait/waitpid的使用)僵尸進程是指的父進程已經(jīng)退出,父進程沒有處理子進程的退出信息(包括子進程的返回值和其他的一些東西),使得已退出的子進程就成為僵尸進程Defunct (zombie)。僵尸進程只是在process table里有一個記錄,沒有占用其他的資源,除非系統(tǒng)的進程個數(shù)的限制已經(jīng)快超過了,zombie進程不會有更多的壞處。通過在父進程里增加一個wait/waitpid可以解決僵尸進程問題。一般來說,當父進程 fork()

13、一個子進程后,它必須用 wait() 或者 waitpid() 等待子進程退出。正是這個wait() 動作完全清除子進程退出后的信息。【例題】設(shè)計一個程序,要求用戶可以選擇是否創(chuàng)建子進程,子進程模仿思科(Cisco)1912交換機的開機界面,以命令行的方式讓用戶選擇進入,父進程判斷子進程是否正常終止。圖1 算法流程/*6-8.c 創(chuàng)建進程(cisco菜單)*/#include /*文件預(yù)處理,包含標準輸入輸出庫*/#include /*文件預(yù)處理,包含fork函數(shù)庫*/#include /*文件預(yù)處理,包含fork、wait、waitpid函數(shù)庫*/#include /*文件預(yù)處理,包含wai

14、t、waitpid函數(shù)庫*/#include /*文件預(yù)處理,包含exit函數(shù)庫*/void display0(); /*子程序聲明*/void display1();void display2();int main () /*程序的主函數(shù),開始入口*/ pid_t result; int status,select,num; void (*fun3)(); /*利用函數(shù)指針建立三個子程序*/ fun0=display0; fun1=display1; fun2=display2; printf(1.創(chuàng)建子進程n2.不創(chuàng)建子進程n請輸入您的選擇:); scanf(%d,&select); if

15、(select=1) /*如果用戶輸入1,創(chuàng)建進程*/ result=fork(); /*調(diào)用fork函數(shù)創(chuàng)建進程,返回值存在變量result中*/ if(result=-1) perror(創(chuàng)建進程出錯); exit(1); if (result=0) /*子進程*/ printf(這是子進程(進程號:%d,父進程號:%d): ,getpid(),getppid(); printf(進入思科(Cisco)1912交換機開機界面。n ); printf(1 user(s) now active on Management Console.n); printf(tUser Interface M

16、enun); printf(t0 Menusn); printf(t1 Command Linen); printf(t2 IP Configurationn); printf(Enter Selection:); scanf(%d,&num); /*運用函數(shù)指針,運行相應(yīng)的子程序*/ if(num=0&num=2) (*funnum)(); exit(0); else waitpid(result,&status,0); /*父進程調(diào)用waitpid函數(shù),消除僵尸進程*/ printf(這是父進程(進程號:%d,父進程號:%d)n ,getpid(),getppid(); if(WIFEXI

17、TED(status)=0) printf(子進程非正常終止,子進程終止狀態(tài):%dn, WIFEXITED(status); else printf(子進程正常終止,子進程終止狀態(tài):%dn, WIFEXITED(status); exit(0); /*子程序部分*/void display0() printf(您選擇進入了菜單模式n);void display1() printf(您選擇進入了命令行模式n);void display2() printf(您選擇進入了IP地址配置模式n);【步驟 1】: 設(shè)計編輯源程序代碼 rootlocalhost root#vim 6-8.c【步驟 2】:用

18、gcc編譯程序rootlocalhost root#gcc 6-8.c o 6-8【步驟 3】:運行程序 rootlocalhost root#./6-81.創(chuàng)建子進程2.不創(chuàng)建子進程請輸入您的選擇:2這是父進程(進程號:5028,父進程號:4739)子進程非正常終止,子進程終止狀態(tài):0再次運行程序rootlocalhost root#./6-8 1.創(chuàng)建子進程2.不創(chuàng)建子進程請輸入您的選擇:1 這是子進程(進程號:5044,父進程號:5043): 進入思科(Cisco)1912交換機開機界面。 1 user(s) now active on Management Console. User

19、Interface Menu 0 Menus 1 Command Line 2 IP ConfigurationEnter Selection:0 您選擇進入了菜單模式這是父進程(進程號:5043,父進程號:4739)子進程正常終止,子進程終止狀態(tài):1 【步驟4】:修改程序試著不用waitpid函數(shù),如下所示:/waitpid(result,&status,0); /*父進程調(diào)用waitpid函數(shù),消除僵尸進程*/再次運行程序rootlocalhost root#./6-8 1.創(chuàng)建子進程2.不復(fù)創(chuàng)建子程請輸入您的選擇:1 這是子進程(進程號:5067,父進程號:5064): 進入思科(Cis

20、co)1912交換機開機界面。 1 user(s) now active on Management Console. User Interface Menu 0 Menus 1 Command Line 2 IP ConfigurationEnter Selection:這是父進程(進程號:5064,父進程號:4739)子進程非正常終止,子進程終止狀態(tài):02)Linux守護進程守護進程(Daemon)是運行在后臺的一種特殊進程。它獨立于控制終端并且周期性地執(zhí)行某種任務(wù)或等待處理某些發(fā)生的事件。守護進程的特性:(1)守護進程最重要的特性是后臺運行。(2)守護進程必須與其運行前的環(huán)境隔離開來。這

21、些環(huán)境包括未關(guān)閉的文件描述符,控制終端,會話和進程組,工作目錄以及文件創(chuàng)建掩碼等。這些環(huán)境通常是守護進程從執(zhí)行它的父進程(特別是shell)中繼承下來的。(3)守護進程的啟動方式有其特殊之處。它可以在Linux系統(tǒng)啟動時從啟動腳本/etc/rc.d中啟動,也可以由作業(yè)規(guī)劃進程crond啟動,還可以由用戶終端(通常是shell)執(zhí)行。 編寫守護進程的要點:(1) 創(chuàng)建子進程,終止父進程(2) 在子進程中創(chuàng)建新會話(3) 當前工作目錄換成其他的路徑,如“/”或“/tmp”等(4) 把文件創(chuàng)建掩碼設(shè)置為0(5) 關(guān)閉文件描述符【例】設(shè)計兩段程序,主程序6-9.c和初始化程序init.c。要求主程序每

22、隔10秒鐘向/tmp目錄中的日志6-9.log報告運行狀態(tài)。初始化程序中的init_daemon函數(shù)負責生成守護進程。分析 把生成守護進程的部分寫成獨立的函數(shù)init_daemon,放在程序init.c中,方便調(diào)用,程序init.c中要編寫的是前面守護進程的五步。主程序先調(diào)用init_daemon函數(shù),使得主程序運行后成為守護進程,接著主程序用while語句無限循環(huán),每隔10秒鐘往6-9.log文件中寫入一行文字和當前時間。/*6-9.c程序:主程序每隔一分鐘向/tmp目錄中的日志6-9.log報告運行狀態(tài)*/#include /*文件預(yù)處理,包含標準輸入輸出庫*/#include /*文件預(yù)

23、處理,包含時間函數(shù)庫*/void init_daemon(void); /*守護進程初始化函數(shù)*/ int main() /*C程序的主函數(shù),開始入口*/ FILE *fp; time_t t; init_daemon(); /*初始化為daemon*/ while(1) /*無限循環(huán),每隔10秒鐘向6-9.log寫入運行狀態(tài)*/ sleep(10); /*睡眠10秒鐘*/ if(fp=fopen(6-9.log,”a+”) =0)/*打開6-9.log文件,若沒有此文件,創(chuàng)建它*/ t=time(0); fprintf(fp,守護進程還在運行,時間是: %s,asctime(localtim

24、e(&t) ); fclose(fp); /*初始化程序init.c程序代碼如下:init.c程序:生成守護進程*/#include #include #include #include #include #include void init_daemon(void) pid_t child1,child2; int i; child1=fork(); if(child10) /*(1)創(chuàng)建子進程,終止父進程*/ exit(0); /*這是子進程,后臺繼續(xù)執(zhí)行*/ else if(child1 0) perror(創(chuàng)建子進程失敗); /*fork失敗,退出*/ exit(1); setsid(); /*(2)在子進程中創(chuàng)建新會話*/ chdir(/tmp); /*(3)改變工作目錄到/tmp*/ umask(0); /*(4)重設(shè)文件創(chuàng)建掩碼*/ for(i=0;i NOFILE;+i) /*(5)關(guān)閉文件描述符*/ close(i); return;【步驟 1】:設(shè)計編輯源程序代碼rootlocalhost root#vim 6-9.c rootlocalhost root#vim init.c 【步驟 2】:用gcc編譯程序rootlocalhost root#gcc 6-9

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論