PHP 進程詳解
如下內容從《操作系統精髓與設計原理》中總結提煉得出,刪除了大部分對于理解進程有干擾的文字,對進程知識結構進行的梳理。幾乎所有內容為按照書本上摘抄下來的,我目前還總結提煉不出像作者這么深刻的見解。那么就先學習等完全理解透了,再用自己的語言表達出來。它山之石,可以攻玉。
進程的概念是操作系統的結構的基礎。Multics的設計者在20世紀60年代首次使用了這個技術詞語,它比作業更通用一些。關于進程的定義,如下所示:
1.一個正在執行的程序。
2.計算機中正在運行的程序的一個實例。
3.可以分配給處理器并由處理器執行的一個實體。
4.由單一的順序的執行線程、一個當前狀態和一組相關的系統資源所描述的活動單元。
也可以把進程當成由一組元素組成的實體,進程的兩個基本的元素是程序代碼
(可能被執行相同程序的其他進程共享)和代碼相關聯的數據集
。假設處理器開始執行這個程序代碼,且我們把這個執行實體叫做叫做進程
。在進程執行時,任意給定一個時間,進程都可以唯一的被表征為以下元素。
1.標識符:跟這個進程相關的唯一標識符,用來區別其他進程。
2、狀態:如果進程正在執行,那么進程處于運行態。
3、優先級:相對于其他進程的優先級
4、內存指針:包括程序代碼和進程相關數據的指針,還有和其他進程共享內存塊的指針。
5、上下文數據:進程執行時處理器的寄存器中的數據。
6、I/O 狀態信息:包括顯示的I/O操作。分配給進程的I/O設備(例如磁帶驅動器)和被進程使用的文件列表等。
7、記賬信息:可能包括處理器時間綜合、使用的是時鐘數總和、時間限制、記賬號等。
如下圖:
1、為什么設計了進程?
設計出一個能夠協調各種不同活動的系統軟件是非常困難的。在任何時刻都有許多作業在運行中,每個作業都包括要求按照順序執行的很多步驟,因此分析時間的序列組合是不可的。由于缺乏能夠在所有活動中進行協調和合作的系統級的方法,程序員只能基于他們對操作系統所控制的環境的理解,采用自己的特殊方法。然而這種方法是很脆弱的,尤其對于一些程序設計中的小錯誤,因為這些錯誤只有在很少見的時間序列發生時才會出現。由于需要從應用程序軟件錯誤和硬件錯誤中區分出這些錯誤,因而診斷工作是很困難的。及時檢測出錯誤,也很難確定原因,因為很難在線錯誤產生的精確場景。一般而言,產生這類錯誤的4個主要原因如下:
1.不正確同步
2.失敗互斥。
3.不確定的程序操作
4.死鎖
以上詳細描述請參閱:《操作系統精髓與設計原理》第六版第二章或查看網頁版】
解決這些問題需要一種系統級別的方法監控處理器中不同程序的執行。進程的概念為
此提供了基礎。 因此進程可以看做是由三部分組成的:
1.一段可以執行的程序
2.程序所需要的相關數據
3.程序的執行上下文
2、了解進程執行上下文
執行上下文是進程的重重之中。執行上下文(execution context)
又稱作進程狀態(process state)
,是操作系統用來管理和控制進程所需的內部數據。這種內部信息和進程是分開的,因為操作系統信息不允許被進程直接訪問。上下文包括操作系統管理進程以及處理器正確執行進程所需要的所有信息。包括了各種處理器寄存器的內容,如程序計數器和數據寄存器。它還包括操作系統使用的信息,如進程優先級以及進程是否在等待特定 I/O事件的完成。
圖1
圖1 兩個進程A 和B ,存在于內存中某部分。也就是說給每個進程(包含程序、數據和上下文信息)分配一塊存儲器區域,并且在由操作系統建立和維護的進程表中進行記錄。進程表中包含記錄每個進程的表現,表項內容包括指向包含進程的存儲塊地址的指針,還包括該進程的部分或全部執行上下文。指向上下文的其余部分存放在別處,可能和進程自己保存在一起,通常也可能保存在內存里一塊獨立的區域中。進程索引寄存器(process index register)
包含當前正在控制處理器的進程在進程表中的索引。程序計數器
指向該進程中下一條待執行的指令。基址寄存器(base register)
和界限寄存器(limit register)
定義了該進程所占據的存儲器區域:基址寄存器
中保存了該存儲器區域的開始地址,界限寄存器
中保存了該區域的大小(以字節或字為單位)。程序計數器和所有的數據引用相對于基址寄存器
被解釋,并且不能超過界限寄存器
中的值,這就可以保護內部進程間不會相互干涉。(解決了互斥的問題)
圖1進程索引寄存器
表明進程B正在執行。以前執行的進程被臨時中斷,在A中斷的同時,所有的寄存器的內容被記錄在它執行上下文環境中,以后操作系統就可以執行進程切換,恢復進程A的執行。進程切換過程包括保存B的上下文和恢復A的上下文。當在程序計數器
中載入指向A的程序區域的值時,進程A自動恢復執行。
因此進程被當做數據結構來實現。一個進程可以是正在執行,也可是等待執行。任何時候整個進程狀態都包含在它的執行上下文環境中。這個結構使得可以開發功能強大的技術,以確保在進程中進行協調和合作。在操作系統中可能會設計和并入一些新的功能(優先級,linux中nice值。)這可以通過擴展上下文環境以包括支持這些特征的新信息。
3、兩狀態進程模型
操作系統的基本職責是控制進程的執行。這包括確定交替執行的方式和給進程分配資源在設計控制進程的程序時,第一步就是描述進程所表現出的行為。
由前面的基礎知識介紹可知,在任何時刻,一個進程要么正在執行,要么沒有執行,因而可以構造最簡單的模型。一個進程可以處于以下兩種狀態之一:運行態或未運行態。當操作系統創建一個新的進程時,它將該進程運行態加入到系統中,操作系統知道這個進程是存在的,并且正在等待執行機會。當前正在運行的進程時不時的被中斷,操作系統中的分派器
部分將選擇一個新進程運行。前一個進程從運行態轉換到未運行狀態,另外一個集成轉換到運行態。如下圖.
從這個簡單的模型可以意識到操作系統的一些設計元素。必須用某種方式來表示每個進程,使得操作系統能夠跟蹤它,也就是說,必須有一些與進程相關的信息,包括進程在內存中的當前狀態和位置,即進程控制塊
。未運行的進程必須保持在某種類型的隊列中,并等待它們的執行時機。結構中有一個隊列,隊列中的每一項都指向某個特定進程的指針,或隊列可以由數據塊構成的鏈表組成,每個數據塊表示一個進程。如下圖
因此可以用該隊列圖描述分派器
的行為。被中斷的進程轉移到等待進程隊列中,或者,如果進程已經結束或取消,則被銷毀(離開系統)。在任何一種情況下,分派器
均從隊列中選擇一個進程來執行。
4、進程的創建和終止
進程創建
傳統地,操作系統創建進程的方式對用戶和應用程序都是透明的,這在當代操作系統中也很普遍。但是允許一個進程引發另一個進程的創建將是很有用的。例如一個程序進程可以產生另一個進程,以接受應用程序產生的數據,并將數據組織成適合以后分析的格式。新進程與應用程序并行
的運行,并當得到新的數據時被激活。這個方案對于構造應用程序是非常有用的,例如,服務器進程(如打印服務器、文件服務器)可以為它處理的每個請求產生一個新進程。當操作系統為另一個進程的顯式請求產生一個新進程時,這個動作稱為進程派生。
當一個進程派生另一個進程時,前一個稱作父進程
,被派生的進程稱作子進程
。在典型的情況下,相關進程需要像話之間通信和合作。對程序員來說,合作是一個非常困難的任務。
進程終止
以下事件會導致進程終止,尤其注意最后兩種事件。父進程終止與父進程請求終止子進程。
5、進程的五狀態模型
如果所有的進程都做好了執行準備。隊列是先進先出(first-in-first-out)
的表,對于可運行的進程處理器以一種輪轉(round-robin)
方式操作(依次給隊列中的每個進程一定的執行時間,然后進程返回隊列,阻塞情況除外)。但是存在著一些非運行狀態但已經就緒等待執行的進程,而同時存在另外的一些處于阻塞狀態等待I/O操作結束的進程。因此,如果使用單個隊列,分派器不能只考慮隊列中最老的進程,相反,他應該掃描這個列表,查找那些被阻塞且在隊列中時間最長的進程。
解決這種情況的一種比較自然的方法是將非運行狀態分成兩個狀態:就緒(ready)
和阻塞(blocked)
,此外應該增加兩個已經證明很有用的狀態。
運行態:該進程正在執行。假設計算機只有一個處理器,因此一次最多只有一個進程處于這個狀態。
就緒態:進程做好了準備,只要有機會就開始執行。
阻塞/等待態:進程在某些事件發生前不能執行,如I/O操作完成。
新建態:剛剛創建的進程,操作系統還沒有把它加入到可執行進程組中。通常是進程控制塊已經創建但還沒有加載到內存中的新進程。
退出態:操作系統從可執行進程組中釋放出的進程,或者是因為它自身停止了,或者是因為某種原因被取消。
新建態
和退出態
對進程管理是非常有用的。新建狀態對應于剛剛定義的進程。例如,如果一位新用戶試圖登錄到分時系統中,或者一個新的批作業被提交執行,那么操作系統可以分兩步定義新進程。首先,操作系統執行一些必需的輔助工作,將標識符關聯到進程,分配和創建管理進程所需要的所有表。此時,進程處于新建狀態,這意味著操作系統已經執行了創建進程的必需動作,但還沒有執行進程。
例如,操作系統可能基于性能或內存局限性的原因,限制系統中的進程數量。當進程處于新建態時,操作系統所需要的關于該進程的信息保存在內存中的進程表中,但進程自身還未進入內存,就是即將執行的程序代碼不在內存中,也沒有為與這個程序相關的數據分配空間。當進程處于新建態時,程序保留在外存中,通常是磁盤中。
類似地,進程退出
系統也分為兩步。首先,當進程到達一個自然結束點時,由于出現不可恢復的錯誤而取消時,或當具有相應權限的另一個進程取消該進程時,進程被終止;終止使進程轉換到退出態,此時,進程不再被執行了,與作業相關的表和其他信息臨時被操作系統保留起來,這給輔助程序或支持程序提供了提取所需信息的時間。一個實用程序為了分析性能和利用率,可能需要提取進程的歷史信息,一旦這些程序都提取了所需要的信息,操作系統就不再需要保留任何與該進程相關的數據,該進程將從系統中刪除。
6、UNINX的獨特進程
UNINX 中有兩個獨特的進程。進程0是一個特殊的進程,實在系統啟動時創建的。實際上,這是預定義的一個數據結構,在啟動時被加載,是交換進程。此外,進程0產生進程1,稱作初始進程,進程1是系統中的所有其他進程的祖先。當新的交互用戶登錄到系統是,由進程1為該用戶創建一個用戶進程。隨后,用戶進程可以創建子進程,從而構成一棵分支書,因此任何應用程序都是由一組相關進程組成的。
7、進程控制結構:
此部分對于了解線程特別重要。
此部分對于了解線程特別重要。
此部分對于了解線程特別重要。
一個進程至少包括足夠的內存空間,以保存該進程的程序和數據;此外,程序的執行通常涉及用于跟蹤過程調用和過程間參數傳遞的棧。最后,與每個進程相關聯的還有操作系統用于控制進程的許多屬性,通常:
屬性的集合稱作進程控制塊
。
程序、數據、棧、屬性的集合稱作進程映像
下圖經過了我的重新繪制,希望能夠比書本上更加易懂。
以上為進程控制塊、進程映像的關系。后續的文章會繼續沿著進程、線程的方向去走。爭取整理出一套涉及PHP進程、子進程、線程、協程的相關理論與實踐文章。
吃飯去嘍。