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

下載本文檔

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

文檔簡(jiǎn)介

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

2、,而 exec 調(diào)用則會(huì)用新程序代替當(dāng)前進(jìn)程上下文。exec系列函數(shù)并不創(chuàng)建新進(jìn)程,調(diào)用exec前后的進(jìn)程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 ch

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

4、,system將外部可執(zhí)行程序加載執(zhí)行完畢后繼續(xù)返回調(diào)用進(jìn)程。system的返回值就是被加載的程序的返回值。/* systemtest.c for test System. 調(diào)用system創(chuàng)建進(jìn)程*/#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è)計(jì)一個(gè)程序,用fork函數(shù)創(chuàng)建一個(gè)子進(jìn)程,在子進(jìn)程中,要求顯示子進(jìn)程號(hào)與父進(jìn)程號(hào),然后顯示當(dāng)前目錄下的文件信息,在父進(jìn)程中同樣顯示子進(jìn)程號(hào)與父進(jìn)程號(hào)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(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ì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論