




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
操作系統中進程管理的基本原理作者:石瑩(2010-6-27)作者信箱:wondersy0618@163.com刖言文章借助王爽老師編寫的Toyix操作系統,通過對一個個程序的執行結果的分析,向讀者演示了操作系統中進程的基本原理和基本特性。這篇文章面向已經掌握c語言和數據結構的操作系統的初學者。讀者除了學習其中的知識,更應該學習體會文章中分析探索問題的方法,并在以后的計算機學習中應用這些方法。這些學習的能力是比知識更重要的東西。文章在編寫過程中參考了Toyix簡易教程,《計算機操作系統》(西安電子科技大學出版社),《匯編語言》(王爽)操作系統發展的意義在沒有出現操作系統以前,計算機只能在一段時間執行一段程序,程序因為IO請求等原因發生阻塞時,CPU會處于空閑狀態造成資源的浪費。因為早期的計算機價格昂貴,用戶就希望可以更高效的利用計算機資源。這種需求就促進了操作系統的產生和發展。進程我們今天使用的操作系統主要是分時系統,由調度程序調入的多個作業共享CPU資源,其中每個作業只執行極短的一段時間(比如0.1S,我們稱為一個時間片),極短的時間過后暫停執行,調入下一個程序。這樣在不長的一段時間內(比如5s內),有限的進程(少于50個)都可以得到至少一次的執行,用戶請求可以得到及時的響應。這種作業調度的方式我們稱為時間片輪轉法。這種執行的方式叫并發執行,并發性也是分時系統的基本特性之一。在分時系統中,為了執行一項作業,就需要把要執行的作業程序載入內存中作為程序段,為作業分配相應的數據空間作為數據段,并加入一個控制塊(PCB),用來保存當前作業執行所必須的一些信息,使之能夠并發執行。內存中的程序段、數據段和PCB我們稱為一個進程實體,而一個進程實體的執行過程我們稱為進程。
進程的三種基本狀態我們已經知道了進程實際是一個動態的概念,我們再回到分時系統的原理上。分時系統是給一個進程分配一個時間片,讓這個進程執行,當進程時間片用完以后,為下一個進程分配時間片。當進程執行過程中發生阻塞,則主動讓出CPU控制權,給其它進程執行的機會。分析上面的過程,每一時刻只有一個進程處于執行的狀態。而有多個進程處于等待分配時間片的狀態,這多個進程應該遵循一定的順序。事實上是存在于一個隊列中。這種等待分配時間片的狀態我們稱為就緒狀態,存放就緒進程的隊列就稱為就緒隊列。當CPU處于空閑狀態時,調度程序就會從就緒隊列中取出一個進程并執行。當進程時間片用完后,調度信息就會把這個進程放入到就緒隊列中。除了時間片用完,當進程IO請求時,進程會在IO請求完畢之前無法繼續執行,這類情況我們稱為進程的阻塞(可能出現進程阻塞的有IO請求,申請緩沖空間等)。當出現進程阻塞后,調度程序應該怎么處理呢?首先進程肯定不能放入就緒態,因為放入就緒態就有可能被分配時間片,而此時進程不能繼續執行,這就浪費了CPU資源。調度程序對其進行的處理是將其放到一個阻塞隊列中,當10完成時,再把它放回就緒隊列等待分配時間片。圖1進程就緒態、執行態和阻塞態的關系圖1圖1進程就緒態、執行態和阻塞態的關系使用Toyix查看進程的三種狀態Toyix是一個專門為操作系統的基礎理論教學而編寫的系統,通過這個系統可以很方便的模擬進程的創建執行過程。啟動toyix系統,如圖從Toyix網站(/)下載系統并安裝(具體安裝方式請參考網站教程)啟動toyix系統,如圖Toyix操作系統支持絕大部分常用的dos命令,我們可以使用dos下的編程方式進行編程。可以使用dos下的工具編寫程序源碼,如圖<Co->C:>edit1-c下面我們編寫一個程序,用來演示程序的三種狀態#include<toyix.h>main()(inti;for(i=0;i<80;i++)(put_str(3,i,2,"a");delay(30);}get_char();for(i=0;i<80;i++)(put_str(5,i,2,"b");delay(30);}分析上面的程序,程序中引入toyix庫toyix.h文件是為了使用toyix系統提供的關于的函數。程序首先在循環內調用put_str在屏幕第三行輸出字符a(關于put_str的用法,請參考toyix函數手冊),每輸出一次延時30ms。然后調用get_char函數阻塞式獲得用戶輸入。最后再通過一個循環在屏幕第五行輸出一行字符b。下面我們在toyix下編譯這個程序。toyix提供的c語言編譯命令是cc,使用方式是“ccc語言源文件文件名”,如圖<Co->C:>cc1-cCompiling...1.c:Auailablememovy208664Linking...Making...1-prg<Co.>C:>程序已經編譯,連接成功,產生了toyix下的可執行文件2.prg,prg是toyix下可執行文件的后綴名。下面運行這個程序。Toyix中運行一個可執行文件的命令是do,使用方法是“do可知性文件的文件名”,注意不需要加后綴名,如圖<Co.>C:>do1然后以后就看到了toyix程序運行時的界面blocked:ToyixMultiprocessMonitorU0.03
blocked:ToyixMultiprocessMonitorU0.03屏幕上邊的藍條是toyix進程監視器,通過它我們可以方便的知道每個進程所處于的狀態。其中running后指示的是處于運行狀態的進程id,ready后指示的是處于就緒狀態的進程id,blocked指示的是處于阻塞狀態的進程id。可以看到我們的程序已經準備完畢,按任意鍵開始執行。程序應該是處于就緒態,進程id是1。而此時沒有更多的任務,CPU處于空閑狀態,running處用一個紅色的0表示。按任意鍵開始執行程序running:1ready: blocked: ToyixMultiprocessMonitoruO.S31.prgokHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa程序開始在屏幕輸出a,此時程序處于運行態。一行輸出完畢,程序會請求用戶輸入,如圖running:0ready: blocked:1 ToyixMultiprocessMonitorU0.031.prg<15ok可以看到ID為1的進程此時處于阻塞態。按任意鍵,使程序繼續執行running:1ready: blocked: ToyixMultiprocessMonitoru0.031.prg<1>okaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb如圖,程序進入運行態繼續輸出字符b,知道程序運行結束。事實上,進程應該有一個進入就緒態的過程,再由操作系統取出就緒進程分配時間片后進入運行態,但是因為時間太短(Toyix系統每個時間片大概是50ms),我們沒有看到那個狀態。進程與輕權進程我們已經知道,操作系統的多個進程處于并發執行的狀態。一個進程p1可以創建另一個進程p2,我們稱p2為p1的子進程,p1為p2的父進程。每個進程都會有一個進程實體,下面我們研究父進程與子進程進程實體之間的聯系我們可以應用c語言的某些特性來進行研究,比如我們可以通過下面的程序來輸出一個變量在內存中的位置#include<toyix.h>inti=0;main()(printf("\n%d:%d\n",_DS,&i);} —blocked:ToyixMultiprocessMonitoru0.03執行后就得到了變量i的段地址和偏移地址(4324d:3216d)blocked:ToyixMultiprocessMonitoru0.03running:0ready4.prg<1>okPress key■■■4324:3216
也可以通過下面這段程序來打印main函數的地址#include<toyix.h>inti=0;main()(printf("\n%d:%d\n",_CS,main);} —blocked:ToyixMultiprocessMonitoru0.03執行后獲得了main函數的段地址和偏移地址(4324d:0785dblocked:ToyixMultiprocessMonitoru0.03running:0ready4.prg<1>okPressemykey■■■4324:785通過以上兩種方法,我們可以得到一個進程的數據和代碼在內存中的位置。Toyix為我們提供了兩個簡單的創建進程的函數fork()和frk(),這兩個函數的調用方法我們不做具體介紹,請參考toyix的函數手冊。下面我們分別研究這兩個函數創建進程的差別。編寫下面的程序#include<toyix.h>inti=-1;main()(i=fork();printf("\n\n\nCallforkreturnvalueis%d\n",i);printf("\nPID=%d\n",get_pid());printf("\nFunctionmainoftheaddressis%d:%d\n",_CS,main);printf("\nVariableioftheaddressis%d:%d\n",_DS,&i);delay(500);}分析這個程序,這個程序調用fork()函數創建的新的進程,并在每個進程中輸出fork()函數返回值(判斷父進程還是子進程),當前進程ID,main函數的地址,變量i的地址。運行這個程序如圖,通過fork()函數的返回值我們判斷,pid為1的進程為父進程。而且父進程與子進程數據段和代碼段均不相同。這說明通過fork()函數創建的進程數據與代碼不共享。下面我們用同樣的方法研究通過frk()函數創建的進程,修改上面的程序#include<toyix.h>inti=-1;main()(i=frk();printf("\n\n\nCallforkreturnvalueis%d\n",i);printf("\nPID=%d\n",get_pid());printf("\nFunctionmainoftheaddressis%d:%d\n",_CS,main);printf("\nVariableioftheaddressis%d:%d\n",_DS,&i);delay(500);}這個程序與上面的程序基本相同,只是把fork()函數改為了frk()函數,在toyix中運行這個程序我們發現,pid為1的進程為父進程,父進程與子進程代碼段不同,但是數據段相同。這說明,通過frk()創建的進程數據段共享,代碼段不共享。這種進程我們稱為輕權進程。我們為什么要創建輕權進程呢?創建進程是為了提高系統資源利用率,但是因為進程擁有自己的數據段。進程的創建需要申請數據空間,銷毀需要釋放數據空間,切換進程需要保存并重新設置CPU寄存器現場。進程的創建,切換和銷毀都需要消耗大量的CPU資源。有時我們需要把自己的一個進程分成幾部分同時處理。比如程序中有一段代碼會循環等待用戶輸入,而用戶的是否輸入并不會影響我們程序的繼續運行,我們不希望等待用戶輸入時主程序也進入阻塞狀態。我們可以將用戶輸入的部分創建一個新的進程,但是事實上這個進程并不需要分配新的數據空間。那么就出現了沒有自己獨立的數據空間的進程,也就是輕權進程。輕權進程在創建,切換和銷毀時消耗的資源比進程都小的多。下面我們做這樣一個實驗。編寫下面的程序#include<toyix.h>main()(frk();printf("\nPID=%d\n",get_pid());} —程序中調用frk()創建輕權進程以后每個進程打印自己的進程id。在toyix下運行并查看結果running-prg<1>ressan</ID=10readyrunning-prg<1>ressan</ID=10readyokkey-..blockedToyixMultiprocessMonitoru0.可以看到運行結果與我們預想的不太一樣,只打印了一個進程的pid,另一個沒有打印。這是為什么呢?我們修改一下這個程序#include<toyix.h>main()(frk();printf("\nPID=%d\n",get_pid());delay(100);與前一個比較,這個程序多調用了一個延時功能。再看運行結果runn:0ready:okkey...blockedToyixMultiprocessMonitoru0.03runn:0ready:okkey...blockedToyixMultiprocessMonitoru0.03我們發現現在的顯示結果正確了。現在為什么正確了呢?我們分析第一個程序,主進程創建進程以后,打印輸出自己的進程id。此時子進程還沒有得到執行的機會,父進程就運行結束了,子進程也被銷毀。子進程雖然創建了,但是并沒有得到執行。所以出現了錯誤的結果。第二個程序中,在父進程打印出自己的進程id以后,通過延時給子進程執行的機會,子進程進入運行態,打印子進程pid,輸出結果正常。以上分析表明,如果父進程結束,操作系統會銷毀它創建的所有輕權進程。這很容易理解,因為輕權進程是沒用數據空間的,它共享父進程的數據空間。而父進程銷毀時,數據空間會被釋放,此時如果子進程繼續執行,可能訪問已經釋放掉的空間,這是不安全的。這一部分我們講述了進程與輕權進程的一些差別。簡單來說,進程是可以獨立運行的最小單位。而輕權進程是可供操作系統調度的最小單位。后面我們要繼續講述怎樣在我們編寫的程序中更方便的創建多個輕權進程。使用cobegin創建輕權進程通過以上的學習我們知道,為了更高效的利用資源,我們編寫的程序可能要創建多個輕權進程。但是使用frk()創建的進程只能在兩個進程中執行同一段代碼,這樣的進程是沒有實際意義的。為了方便的創建輕權進程,toyix為我們提供了cobegin函數。Toyix函數手冊中對這個函數的描述如下:原型:intcobegin();功能:創建多個子進程并發執行函數參數:函數名用0結束,例如:cobegin(f1,f2,f3,0);返回:創建子進程的個數說明:所有子進程共享數據段,主進程撤銷,所有子進程將被撤銷。我們編寫一個程序,通過cobigin函數來創建多個輕權進程。#include<toyix.h>voidf1()(printf("\nfunctionf1,pid=%d\n",get_pid());TOC\o"1-5"\h\z} —voidf2()(printf("\nfunctionf2,pid=%d\n",get_pid());} —voidf3()(printf("\nfunctionf3,pid=%d\n",get_pid());} —main()(printf("\nfunctionmain,pid=%d\n",get_pid());cobegin(f1,f2,f3,0);delay(100);}在這個程序中,main函數首先輸出自己的pid,然后調用cobegin函數將f1,f2,f3函數分別作為一個輕權進程運行,在每個輕權進程里,打印自己的函數名和pid。運行結果如圖多進程引發的問題下面我們要應用多進程技術編寫一個模擬火車售票系統的程序。在火車票售票中心的服務器上,保存著未售出的火車票數量。而各地有很多代售點,他們在售票時會連接到售票中心檢查火車票剩余情況,如果還有剩余票,那么賣出這張牌,同時通知售票中心車票被賣出。編寫程序實現這個過程,首先創建一個全局變量,用來保存剩余票數。編寫一個函數用來模擬一個售票窗口的售票流程。再通過在main函數中調用cobegin函數創建多個輕權進程,模擬多個窗口售票。程序代碼如下:
#include<toyix.h>inttotal=10;voidf1()(while(total>0)(delay(50);printf("\npid=%d,sellticket:%d",get_pid(),total--);} —}main()(cobegin(f1,f1,0);getch();}在單個窗口的售票流程中,首先檢查剩余票數是否大于0,如果大于0,那么延時一段時間(模擬真實情況),然后賣出這張票,再令剩余票減一。在toyix系統中運行,模擬結果如圖running:1ready:1.prg<1>okPressanyke</.--pid=2,sellticketpid=3,sellticketpid=2,sellticketpid=3,sellticketpid=2,sellticketpid=3,sellticketpid=2,sellticketpid=3,sellticketpid=2,sellticketpid=3,sellticketpid=2,sellticketrunning:1ready:1.prg<1>okPressanyke</.--pid=2,sellticketpid=3,sellticketpid=2,sellticketpid=3,sellticketpid=2,sellticketpid=3,sellticketpid=2,sellticketpid=3,sellticketpid=2,sellticketpid=3,sellticketpid=2,sellticket019876543210blocked:ToyixMultiprocessMonitoruS.03我們發現一個問題,售票窗口售出了0號票,這在實際應用中是不允許的。為什么會發生這種情況呢?我們再分析剛才的程序,為了分析簡單,我們假設假如程序運行了一段時間,還有一張票未售出。程序中每個輕權進程的執行過程如下圖所示。(虛線代表阻塞態或就緒態,實現代表運行態)total:total:主進程:主進程創建完輕權進程P1和P2后,在獲得用戶鍵盤輸入之前一直處于阻塞態沒有獲得時間片主進程:a)P1獲得時間片,檢測到total>0,進入售票程序延時一段時間,還未售票時間片已經用完輕權進程P1:c)P1獲得時間片繼續運行,售票程序售出這張票后,令total減一。再次檢測total=0,循環結束,進程結束b)P2獲得時間片,與a中處理過程相同輕權進程P2: id)P2獲得時間片,售票后退出。但是此時total=0,所以售出了0號票此時一個進程(pid=2)檢查total的值,檢測到大于0進入售票程序,調用delay延時(注意票并沒有售出,tatal仍為1)。此時另一個輕權進程(pid=3)獲得了時間片開始運行,仍會檢測tatal的值,同樣進入了售票程序,調用delay延時。調度程序調出剛才的輕權進程(pid=2)的進程繼續執行,售出1號票并將票數減1,再次檢測tatal小于0,pid為2的輕權進程結束退出。Pid為3的輕權進程回到剛才的狀態繼續售票,而此時tatal為0,所以售出了0號票。顯然,在這個實驗中如果沒有延時操作,可能不會出現這樣的情況。但是在一個長期運行的多個輕權進程的系統中,很有可能出現這種兩個輕權進程訪問同一資源時出錯的問題。增加一個延時只是放大了這種問題。通過上述分析,我們了解了一個進程通過創建多個輕權進程雖然可以提高資源的利用率,但是在訪問同一資源時可能引起一些問題。為了解決這些問題,我們必須在不同輕權進程訪問同一資源時進行一些判
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 《初中立定跳遠教學課件》
- 2024年鉗工四級理論知識題庫(附答案解析)
- 企業網絡設計方案
- 膠合板生產過程中的能源消耗與節能措施考核試卷
- 《創傷性脾破裂》教學課件
- 洗浴行業服務品質保障措施實施考核試卷
- 稀有稀土金屬加工中的行業政策研究與分析考核試卷
- 礦山設備與機械自動化技術研究考核試卷
- 絕緣橡膠制品與應用考核試卷
- 貨幣經紀公司客戶服務體驗提升考核試卷
- 70歲以上老人考駕照,三力測試題庫答案
- 2023年副主任醫師(副高)-中醫婦科學(副高)考試上岸歷年考點真題演練含答案
- 醫院預算業務流程圖
- ALeader 阿立得 ALD515使用手冊
- 政教主任國旗下的講話稿-講話稿
- 國學文化古典中國風模板
- 國民經濟核算司精講GDP核算
- 畢業論文PLC在機械手控制系統中的應用
- HY/T 0331-2022綠潮生態調查與監測技術規范
- GB/T 7064-2017隱極同步發電機技術要求
- GB/T 31928-2015船舶用不銹鋼無縫鋼管
評論
0/150
提交評論