操作系統實驗,實驗5進程管理_第1頁
操作系統實驗,實驗5進程管理_第2頁
操作系統實驗,實驗5進程管理_第3頁
操作系統實驗,實驗5進程管理_第4頁
操作系統實驗,實驗5進程管理_第5頁
已閱讀5頁,還剩26頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、實驗五 Linux進程管理進程的一生w實驗目的實驗目的熟悉進程及進程控制等基本概念在Linux操作系統中的實現利用Linux提供的系統調用函數/庫函數實現進程管理w實驗準備及預習實驗準備及預習閱讀講義附件6, Linux進程管理,理解進程在其生命周期中的主要狀態及有關操作命令和函數:ps、fork()、exit()、sleep()和wait()進程簡介w問題1:單CPU計算機上在一個時間片斷內只能執行一條指令,那么Linux是如何實現多進程同時執行的呢?wLinux使用了一種稱為“進程調度(process scheduling)”的手段為每個進程指派一定的運行時間(這個時間通常很短,通常以毫秒

2、為單位),然后依照某種規則,從眾多進程中挑選一個投入運行,其他的進程暫時等待當正在運行的那個進程時間耗盡,或執行完畢退出,或因某種原因暫停,Linux就會重新進行調度,挑選下一個進程投入運行每個進程占用的時間片都很短,從使用者的角度來看,就好像多個進程同時運行一樣w在Linux中,每個進程在創建時都會被分配一個數據結構,稱為進程控制塊(Process Control Block,簡稱PCB),PCB中包含了很多重要的信息,供系統調度和進程本身執行使用,其中最重要的莫過于進程ID(process ID)w進程ID也被稱作進程標識符,是一個非負的整數,在Linux操作系統中唯一地標志一個進程,在最

3、常使用的i386架構(即PC使用的架構)上,一個非負的整數的變化范圍是0-32767,這也是所有可能取到的進程IDw從進程ID的名字可看出,它是進程的身份證號碼,每個進程的進程ID不會相同ps命令wps命令的常用選項l:以長格式顯示進程信息ef:顯示系統中所有進程的全面信息aux:顯示所有終端上所有用戶進程的所有信息wps命令是查看進程狀態的最常用的命令,可以提供關于進程的許多信息。根據顯示的信息可以確定哪個進程正在運行、哪個進程被掛起、進程已運行多長時間、進程正在使用的資源、進程的相對優先級,以及進程的標識號(PID)等信息 ps命令各輸出項的含義為:命令各輸出項的含義為:wS(state)

4、:進程狀態,其中R表示運行狀態;S表示休眠狀態;T表示暫停或終止狀態;Z表示僵死狀態wUID(User ID):進程啟動者的用戶IDwPID(ProcessID):進程號wPPID:父進程的進程號wNI(Nice):進程的優先級值wSZ(Size):進程占用內存空間的大小,以KB為單位wTTY:進程所在終端的終端號,其中桌面環境的終端窗口表示為pts/0,字符界面的終端號為tty1tty6.wTIME:進程累計使用的CPU時間wCMD:啟動進程的shell命令fork2.4.4版內核中,fork是第2號系統調用,函數庫中的原型是: #include /* 提供類型pid_t的定義 */ #in

5、clude /* 提供函數的定義 */ pid_t fork(void); wfork系統調用的作用是復制一個進程。當一個進程調用它,完成后就出現兩個幾乎一模一樣的進程,由此得到了一個新進程wLinux中創造新進程的方法只有fork系統調用,其他一些看起來似乎也能創建新進程庫函數,實際上也在內部調用了fork;包括在命令行下運行應用程序,新進程也是由shell調用fork制造出的 問題2:如果fork后子進程和父進程幾乎完全一樣,而系統中產生新進程的唯一方法就是fork,那系統中所有的進程都要一模一樣嗎?如果子進程要執行新的應用程序怎么辦? 例1w在Linux系統中運行下面程序,最多可產生多少

6、個進程?畫出進程家族樹。int main()fork();fork();fork();ABECFDGH分析向下父進程Aint main() fork(); fork(); fork();子進程 Bint main() fork(); fork(); fork(); 子進程 Cint main() fork(); fork(); fork(); 子進程 Fint main() fork(); fork(); fork(); 子進程 Eint main() fork(); fork(); fork();子進程Hint main() fork(); fork(); fork(); 子進程 Dint

7、main() fork(); fork(); fork(); 子進程 Gint main() fork(); fork(); fork(); 返回#include int main() int p1, p2, i; while(p1=fork()= -1); if(p1=0)for(i=0;i3;i+) printf(“child %dn”, p1); printf(“child %d is interrupted, press enter to continue:n”,p1);getchar();for(i=0;i3;i+) printf(“child %dn”, p1); else whi

8、le(p2=fork()= -1); if(p2=0)for(i=0;i3;i+) printf(“child %dn”, p2);printf(“child %d is interrupted, press enter to continue:n”,p2); getchar();for(i=0;i3;i+) printf(“child %dn”, p2); elsefor(i=0;i3;i+) printf(“parentn”);printf(“father is interrupted, press enter to continue:n”); getchar();for(i=0;i3;i

9、+) printf(“parentn”); return 0;例2問題3:如何修改程序,使得在各進程的輸出信息中能顯示自己的進程號? getpid2.4.4版內核中,getpid是第20號系統調用,其Linux函數庫中的原型是: #include /* 提供類型pid_t的定義 */ #include/* 提供函數的定義 */ pid_t getpid(void); getpid的作用很簡單,即返回當前進程的ID,請看的例子:/* getpid_test.c */#include main() printf(The current process ID is %dn,getpid(); w編譯

10、并運行程序getpid_test.c:$gcc -o getpid_test getpid_test.c $./getpid_testThe current process ID is 1980w再運行一遍:$./getpid_testThe current process ID is 1981 自己的運行結果很可能與這個數字不一樣,這很正常盡管是同一個程序,每次運行所分配到的進程標識符都不相同exit2.4.4版內核中exit是第1號調用,原型是: #include void exit(int status); exit用來終止一個進程。無論在程序中的什么位置,只要執行到exit系統調用,進

11、程就會停止剩下的所有操作,清除包括PCB在內的各種數據結構,并終止本進程的運行 /* exit_test1.c */#includemain() printf(this process will exit!n); exit(0); printf(never be displayed!n); 編譯后運行:$gcc -o exit_test1 exit_test1.c$./exit_test1this process will exit!程序并沒有打印never be displayed!/n,因為在此之前,在執行到exit(0)時,進程就已經終止了wexit系統調用帶有一個整型參數status,

12、可利用這個參數傳遞進程結束時的狀態,例如該進程是正常結束/出現某種意外而結束一般地,0表示沒有意外的正常結束;其他的數值表示出現了錯誤,進程非正常結束編程時,可用wait系統調用接收子進程的返回值,從而針對不同的情況進行不同的處理exit和_exit _exit在Linux函數庫中的原型是: #include void _exit(int status);作為系統調用,_exit和exit是一對孿生兄弟_exit()函數最為簡單:直接使進程停止運行,清除其使用的內存空間,并銷毀其在內核中的各種數據結構exit()函數則在這些基礎上作了一些包裝,在執行退出之前加了若干道工序w兩者間的最大區別:e

13、xit()函數在調用exit系統調用之前要檢查文件的打開情況,把文件緩沖區中的內容寫回文件wLinux標準函數庫中,有一套稱作“高級I/O”的函數(printf()、fopen()、fread()、fwrite()都在此列),也稱作“緩沖I/O)”對應每一個打開的文件,在內存中都有一片緩沖區,每次讀文件時,會多讀出若干條記錄,這樣下次讀文件時就可以直接從內存的緩沖區中讀取,每次寫文件的時候,也僅僅是寫入內存中的緩沖區,等滿足了一定的條件(達到一定數量,或遇到特定字符,如換行符/n和文件結束符EOF),再將緩沖區中的內容一次性寫入文件,因此極大地增加了文件讀寫速度為編程帶來了一點點麻煩:可能存在

14、某些數據,我們認為已寫入文件,實際上因為沒有滿足特定的條件,只是保存在緩沖區內,這時如果使用_exit()函數直接關閉進程,緩沖區中的數據就會丟失如果想保證數據的完整性,請使用如果想保證數據的完整性,請使用exit()函數函數/* exit2.c */#includemain() printf(output beginn); printf(content in buffer); exit(0);編譯并運行:$gcc -o exit2 exit2.c$./exit2output begincontent in buffer/* _exit1.c */#includemain() printf(o

15、utput beginn); printf(content in buffer); _exit(0);編譯并運行:$gcc -o _exit1 _exit1.c $./_exit1output beginLinux將標準IO作為文件處理,雖然是一類特殊文件,但從程序員的角度來看,和硬盤上的普通文件并無區別,與所有其他文件一樣,打開后也有自己的緩沖區問題4:為什么兩個程序的執行結果不同? 僵尸進程 w進程調用exit后,進程并非馬上就消失掉,而是留下一個稱為僵尸進程(Zombie)的數據結構w在Linux進程的5種狀態中,僵尸進程是非常特殊的一種:已放棄了幾乎所有內存空間,沒有任何可執行代碼,也

16、不能被調度,僅僅在進程列表中保留一個位置,記載該進程的退出狀態等信息供其他進程收集w當一個進程已退出,但其父進程還沒有調用系統調用wait(稍后介紹)對其進行收集之前的這段時間里,它會一直保持僵尸狀態/* zombie.c */#include #include main() pid_t pid; pid=fork(); if(pid0) /* 出錯處理 */printf(error occurred!n); else if(pid=0) /*子進程 */ exit(0); else /* 父進程 */ sleep(60);/* 休眠60秒,父進程放棄CPU */ wait(NULL); /*

17、 收集僵尸進程 */sleep的作用是讓進程休眠,期間子進程已退出,而父進程正忙著睡覺,不可能對它進行收集,使得子進程能保持60秒的僵尸狀態 編譯程序:$ gcc -o zombie zombie.c后臺運行程序:$ ./zombie &1 1577列舉當前系統內進程:$ ps -ax . . 1177 pts/0 S 0:00 -bash 1577 pts/0 S 0:00 ./zombie 1578 pts/0 Z 0:00 zombie 1579 pts/0 R 0:00 ps -ax注意中間的“Z”,它是僵尸進程的標志,表示1578號進程現在就是一個僵尸進程 w僵尸進程的概念是

18、從UNIX上繼承來的w僵尸進程中保存著很多對程序員和系統管理員非常重要的信息進程是怎么死亡的?是正常退出呢,還是出現了錯誤,還是被其它進程強迫退出的?這個進程占用的總系統CPU時間和總用戶CPU時間分別是多少?發生頁錯誤的數目和收到信號的數目這些信息都被存儲在僵尸進程中,如果沒有僵尸進程,進程一退出,所有與之相關的信息都將消失問題5:如何收集僵尸進程信息,并終結僵尸進程? wait wait的函數原型: #include /* 提供類型pid_t的定義 */ #include pid_t wait(int *status) w進程一旦調用wait,就立即阻塞自己,由wait自動分析是否當前進程

19、的某個子進程已經退出,如果找到一個僵尸子進程,就收集子進程信息,并將其徹底銷毀后返回;如果沒有找到,wait將阻塞在這里w參數status是一個指向int類型的指針,用來保存被收集進程退出時的一些狀態。如果對子進程死因毫不在意,只想撤消僵尸進程,可設這個參數為NULL,即: pid = wait(NULL);w如果成功,wait將返回被銷毀子進程的ID,如果調用進程無子進程,調用失敗,返回-1/* wait1.c */#include #include #include #include main() pid_t pc,pr; pc=fork(); if(pc0) printf(error o

20、curred!n); /* 出錯 */ else if(pc=0) /* 如果是子進程 */ printf(This is child process with pid of %dn,getpid(); sleep(10); /* 睡眠10秒鐘 */ else /* 如果是父進程 */ pr=wait(NULL); /* 在這里等待 */ printf(I catched a child process with pid of %dn),pr); exit(0);waitpidwaitpid系統調用在Linux函數庫中的原型是: #include /* 提供類型pid_t的定義 */ #inc

21、lude pid_t waitpid(pid_t pid,int *status,int options) 本質上,系統調用waitpid和wait的作用完全相同,但waitpid多出了兩個可由用戶控制的參數pid和options,從而為編程提供了更靈活的方式exec w既然所有新進程都是由fork產生的,而且由fork產生的子進程和父進程幾乎完全一樣,那豈不是意味著系統中所有的進程都應該一模一樣了嗎?顯然不是,要解決這些疑惑,就必須提到exec系統調用wLinux中并不存在一個exec()的函數形式,exec指的是一組函數,一共有6個w其中只有execve是真正意義上的系統調用,其它都是在此基礎上經過包裝的庫函數復習int ma

溫馨提示

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

評論

0/150

提交評論