多進程圖像
操作系統記錄進程,并按照合理的次序交替推進(分配資源,不斷調度),提高CPU利用率和程序執行速度,這就是操作系統的多進程圖像。
當操作系統啟動時,多進程圖像就出現了。 在linux內核源碼main.c文件中,對操作系統初始化時,通過fork()
系統調用啟動了1號進程,進行初始化,再啟動shell。 在shell中,我們輸入命令時,會再調用fork()
啟動其他進程。
// main.c
if (!fork()) {init();
}// shell
while(1) {scanf("%s", cmd);if (!fork()) {exce(cmd);}wait();
}
在windows中我們可以通過任務管理器看到所有進程,Linux可以通過輸入top
或ps
命令查看進程,這就實現了進程的可視化。

組織調度交替執行進程
進程隊列
操作系統會將進程劃分成不同的隊列,并用PCB來記錄進程信息。
比如有的進程正在執行的隊列,有的進程在等待被執行的隊列,有的進程在等待硬盤讀取結果的隊列,還有的進程在已經執行結束的隊列。
其實跟我們在食堂排隊一樣,一條隊伍排隊等著打飯,一條隊伍排隊等著打菜,一條隊伍排隊等著打湯。

進程狀態
操作系統通過進程的狀態來劃分不同的隊列。
新建態,剛剛被創建,分配資源。
就緒態,進程已經可以被執行了,等待CPU中。
運行態,進程正在被CPU執行。
阻塞態,進程正在等待,磁盤等IO操作完成返回結果。
終止態,進程執行結束。
操作系統對通過狀態的不同管理進程,將相同狀態的進程連接成一個隊列,通過調度算法不斷交替執行進程,改變進程狀態,從而推進多個進程不斷向前推進。

進程的管理和我們現實生活中處理方式一樣,比如我們去政府大廳辦事,不同窗口的工作人員就是CPU。 在機器正在掃碼領取排隊號的人就處于新建態,正在辦理業務的人就處于運行態,坐在椅子上等的人就處于就緒態,而辦理業務的時候發現身份證沒帶,去一邊等朋友送身份證的人就是阻塞態,辦理完了的人就處于終止態了。
調度算法
進程數量遠大于CPU數量,操作系統就要對進程進行調度,如果調度不合理也會導致效率低的問題,極端情況下CPU無事可干,再比如有的進程比較重要需要優先執行完,操作系統還需要將CPU資源優先分配給這類進程。
總之一個好的調度算法非常重要,這也是很多計算機科學家在不斷研究推進的一個課題。
最簡單的調度算法就是FIFO+優先級。 FIFO就是先進先出算法,高優先級的先被執行,相同優先級下,先進入隊列的先被執行,后進入隊列的后執行。
其他調度算法有興趣可以慢慢研究。
進程切換
進程切換首先修改PCB中的狀態值,并插入到對應的狀態隊列中。
調用schedule()
模塊進行切換,getNext()
可以理解成內部實現了一個調度算法,從就緒隊列中取出下一個可被執行的進程。

PCB信息切換,switch_to()
就先保存被切換的進程信息,再初始化或恢復即將執行的進程信息。
代碼只是簡單描述,實際工作非常復雜。
其實對照我們上面的描述,先將資源,比如寄存器中的值保存到當前進程的PCB中。然后將即將執行的進程信息從PCB中恢復或初始化,比如PCB中保存的寄存器值賦值給寄存器。

多進程的內存隔離
多進程執行過程可能遇到下圖這個問題。
當進程1使用數據的內存地址是進程2代碼的指令地址。 當進程1執行的過程中,有可能在0x100
地址寫入新值,導致進程2被破壞無法執行。

這個問題解決的辦法就是將不同進程使用的內存進行空間分離。
因此需要有個中間帶進行隔離,在進程和物理內存之間引入映射表。 進程使用的內存地址,通過映射表轉換成物理內存地址,從而使不同進程的內存地址進行分離。
如下圖所示,雖然進程1和進程2都使用了內存地址0x100
,但是通過映射表獲取的物理地址分別是0x780
和0x1260
。

操作系統為每個進程的設置的映射表,是按照一定映射規則來的,具體細節不去研究,但是可以保證內存地址空間分離,每個進程都在自己的一畝三分地里面執行。
就好比南京和福州都有鼓樓區,雖然名字一樣,但是南京和福州空間已經分離了,所以各地的人說到鼓樓區并不會沖突。
多進程合作
進程也可以相互合作,但是如果兩個進程共同修改使用相同的數據,可能會導致數據錯亂的問題。
比如一個傳統模型-生產者消費者模型。
生產者進程負責生成數據,消費者進程負責使用數據。
如下圖所示,生產者進程,生產一個數據count++
,當count=10
時,停止生產數據。消費者進程,消費一個數據count--
,當count=0
,停止消費數據。
消費者進程和生產者進程共享了count
。

由于進程是交替執行,有可能生產者進程生產了數據,但是count
還沒有+1,就切換到了消費者進程,導致消費者進程使用的count
的值是錯誤的,從而導致合作結果產生錯誤。

如果要解決這個問題,就需要保證當一個進程正在使用count
時,其他進程不會使用。 其他進程只有等到count
被釋放時,才能使用。
這就是多進程的鎖機制,實現進程同步,后面會詳細說。

總結
操作系統通過PCB保存進程信息。
操作系統根據進程的執行情況設置不同的狀態,并劃分到相應的狀態隊列中,通過調度算法交替切換執行進程。
每個進程通過映射表訪問物理內存地址,實現了不同進程之間的空間隔離。
多進程合作共享數據會可能導致數據不一致等問題,通過鎖機制實現進程同步,合理推進進程順序。
PS: 以上圖片來自MOOC的哈工大李老師的操作系統課程,李老師的課講的非常好,推薦大家觀看學習,如果文章有錯誤之處,歡迎指正,目前還處于學習階段。