OS- -进程详详解
OS- -進程詳詳解
文章目錄
- OS- -進程詳詳解
- 一、進程
- 進程模型
- 進程的創建
- 進程的終止
- 進程的層次結構
- 進程狀態
- 進程的實現
一、進程
-
操作系統中最核心的概念就是進程,進程是對正在運行中的程序的一個抽象。操作系統的其他所有內 容都是圍繞著進程展開的。
-
進程是操作系統提供的最古老也是最重要的概念之一。即使可以使用的 CPU只有一個,它們也支持(偽)并發操作。它們會將一個單獨的CPU抽象為多個虛擬機的CPU。
-
可以說:沒有進程的抽象,現代操作系統將不復存在。
-
所有現代的計算機會在同一時刻做很多事情,過去使用計算機的人(單CPU)可能完全無法理解現在 這種變化
-
舉個例子更能說明這一點:首先考慮一個Web服務器,請求都來自于Web網頁。
-
當一個請 求到達時,服務器會檢查當前頁是否在緩存中,如果是在緩存中,就直接把緩存中的內容返回。
-
如果緩 存中沒有的話,那么請求就會交給磁盤來處理。但是,從CPU的角度來看,磁盤請求需要更長的時 間,因為磁盤請求會很慢。
-
當硬盤請求完成時,更多其他請求才會進入。如果有多個磁盤的話,可以在 第一個請求完成前就可以連續的對其他磁盤發出部分或全部請求。
-
很顯然,這是一種并發現象,需要有 并發控制條件來控制并發現象。
-
現在考慮只有一個用戶的PC。當系統啟動時,許多進程也在后臺啟動,用戶通常不知道這些進程的啟 動,試想一下,當你自己的計算機啟動的時候,你能知道哪些進程是需要啟動的么?
-
這些后臺進程可能 是一個需要輸入電子郵件的電子郵件進程,或者是一個計算機病毒查殺進程來周期性的更新病毒庫。某 個用戶進程可能會在所有用戶上網的時候打印文件以及刻錄CD-ROM,這些活動都需要管理。
-
于是一 個支持多進程的多道程序系統就會顯得很有必要了。
-
在許多多道程序系統中,CPU會在進程間快速切換,使每個程序運行幾十或者幾百毫秒。
-
然而,嚴格 意義來說,在某一個瞬間,CPU只能運行一個進程,然而我們如果把時間定位為1秒內的話,它可能 運行多個進程。這樣就會讓我們產生并行的錯覺。有時候人們說的 偽并行Cpseudoparallelism) 就是這種情況,以來區分多處理器系統(該系統由兩個或多個CPU來共享同一個物理內存)
-
再來詳細解釋一下偽井行:偽并行是指單核或多核處理器同時執行多個進程,從而使程序更快。 通過以非常有限的時間間隔在程序之間快速切換CPU,因此會產生并行感。缺點是CPU時間可 能分配給下一個進程,也可能不分配給下一個進程。
-
因為CPU執行速度很快,進程間的換進換出也非常迅速,因此我們很難對多個并行進程進行跟蹤,所 以,在經過多年的努力后,操作系統的設計者開發了用于描述并行的一種概念模型(順序進程),使得并行更加容易理解和分析
對該模型的探討,也是本篇文章的主題。下面我們就來探討一下進程模型
進程模型
-
在進程模型中,所有計算機上運行的軟件,通常也包括操作系統,被組織為若干順序進程(sequential processes),簡稱為進程(process)。
-
一個進程就是一個正在執行的程序的實例,進程也包括程 序計數器、寄存器和變量的當前值。從概念上來說,每個進程都有各自的虛擬CPU,但是實際情況是 CPU會在各個進程之間進行來回切換。
-
如上圖所示,這是一個具有4個程序的多道處理程序,在進程不斷切換的過程中,程序計數器也在不同 的變化。
-
在上圖中,這4道程序被抽象為4個擁有各自控制流程(即每個自己的程序計數器)的進程,并且每 個程序都獨立的運行。
-
當然,實際上只有一個物理程序計數器,每個程序要運行時,其邏輯程序計數器 會裝載到物理程序計數器中。
-
當程序運行結束后,其物理程序計數器就會是真正的程序計數器,然后再 把它放回進程的邏輯計數器中。
從下圖我們可以看到,在觀察足夠長的一段時間后,所有的進程都運行了,但在任何一個給定的瞬間僅 有一個進程真正運行。
- 因此,當我們說一個CPU只能真正一次運行一個進程的時候,即使有2個核(或CPU),每一個核 也只能一次運行一個線程。
- 由于CPU會在各個進程之間來回快速切換,所以每個進程在CPU中的運行時間是無法確定的。
- 并且 當同一個進程再次在CPU中運行時,其在CPU內部的運行時間往往也是不固定的。
進程和程序之間 的區別是非常微妙的,但是通過一個例子可以讓你加以區分:
- 想想一位會做飯的計算機科學家正在為他 的女兒制作生日蛋糕。
- 他有做生日蛋糕的食譜,廚房里有所需的原諒:面粉、雞蛋、糖、香草汁等。
- 在這個比喻中,做蛋糕的食譜就是程序、計算機科學家就是CPU.
- 而做蛋糕的各種原諒都是輸入數據。
- 進程就是科學家閱讀食譜、取來各種原料以及烘焙蛋糕等一系例了動作的總和。
- 現在假設科學家的兒子跑過來告訴他,說他的頭被蜜蜂蟄了一下,那么此時科學家會記錄出來他做蛋糕這個過程到了哪一步
- 然后拿出急救手冊,按照上面的步驟給他兒子實施救助。
- 這里,會涉及到進程之間的切換,科學家(CPU)會從做蛋糕(進程)切換到實施醫療救助(另一個進程)。
- 等待傷口處理完畢后
- 科學家會回到剛剛記錄做蛋糕的那一步,繼續制作。
- 這里的關鍵思想是認識到一個進程所需的條件,進程是某一類特定活動的總和,它有程序、輸入輸出以 及狀態。
- 單個處理器可以被若干進程共享,它使用某種調度算法決定何時停止一個進程的工作,并轉而 為另外一個進程提供服務。
- 另外需要注意的是,如果一個進程運行了兩遍,則被認為是兩個進程。那么 我們了解到進程模型后,那么進程是如何創建的呢?
進程的創建
-
操作系統需要一些方式來創建進程。下面是一些創建進程的方式
-
?系統初始化(init)
-
?正在運行的程序執行了創建進程的系統調用(比如fork)
-
?用戶請求創建一個新進程
-
?初始化一個批處理工作
-
系統初始化
-
啟動操作系統時,通常會創建若干個進程。其中有些是前臺進程(numerous processes),也就是同 用戶進行交互并替他們完成工作的進程。一些運行在后臺,并不與特定的用戶進行交互。
- 例如,設計一 個進程來接收發來的電子郵件,這個進程大部分的時間都在休眠,但是只要郵件到來后這個進程就會被喚醒。
- 還可以設計一個進程來接收對該計算機上網頁的傳入請求,在請求到達的進程喚醒來處理網頁的傳入請求。
- 進程運行在后臺用來處理一些活動像是e-mail, web網頁,新聞,打印等等被稱為 守護進程(daemons)。
- 大型系統會有很多守護進程。在UNIX中,ps程序可以列出正在運行的進程,在 Windows中,可以使用任務管理器。
-
系統調用創建
-
除了在啟動階段創建進程之外,一些新的進程也可以在后面創建。通常,一個正在運行的進程會發出系 統調用用來創建一個或多個新進程來幫助其完成工作。
-
例如,如果有大量的數據需要經過網絡調取并進 行順序處理,那么創建一個進程讀數據,并把數據放到共享緩沖區中,而讓第二個進程取走并正確處理 會比較容易些。在多處理器中,讓每個進程運行在不同的CPU±也可以使工作做的更快。
-
用戶請求創建
-
在許多交互式系統中,輸入一個命令或者雙擊圖標就可以啟動程序,以上任意一種操作都可以選擇開啟 一個新的進程
-
在基本的UNIX系統中運行X,新進程將接管啟動它的窗口。在Windows中啟動進程 時,它一般沒有窗口,但是它可以創建一個或多個窗口。每個窗口都可以運行進程。通過鼠標或者命令 就可以切換窗口并與進程進行交互。
-
交互式系統是以人與計算機之間大量交互為特征的計算機系統,比如游戲、web瀏覽器,IDE等 集成開發環境。
-
批處理創建
-
最后一種創建進程的情形會在大型機的批處理系統中應用。用戶在這種系統中提交批處理作業。當操作 系統決定它有資源來運行另一個任務時,它將創建一個新進程并從其中的輸入隊列中運行下一個作業。
-
從技術上講,在所有這些情況下,讓現有流程執行流程是通過創建系統調用來創建新流程的。
-
該進程可 能是正在運行的用戶進程,是從鍵盤或鼠標調用的系統進程或批處理程序。這些就是系統調用創建新進 程的過程。該系統調用告訴操作系統創建一個新進程,并直接或間接指示在其中運行哪個程序。
-
在UNIX中,僅有一個系統調用來創建一個新的進程,這個系統調用就是fork 這個調用會創建一 個與調用進程相關的副本。
-
在fork后,一個父進程和子進程會有相同的內存映像,相同的環境字符串和 相同的打開文件。
-
通常,子進程會執行execve或者一個簡單的系統調用來改變內存映像并運行一個 新的程序。
-
例如,當一個用戶在shell中輸出sort命令時,shell會fork-個子進程然后子進程去執行 sort命令。這兩步過程的原因是允許子進程在fork之后但在execve之前操作其文件描述符,以完成標 準輸入,標準輸出和標準錯誤的重定向。
-
在Windows中,情況正相反,一個簡單的Win32功能調用CreateProcess ,會處理流程創建并將 正確的程序加載到新的進程中。
-
這個調用會有10個參數,包括了需要執行的程序、輸入給程序的命令 行參數、各種安全屬性、有關打開的文件是否繼承控制位、優先級信息、進程所需要創建的窗口規格以 及指向一個結構的指針,在該結構中新創建進程的信息被返回給調用者。
-
除了 CreateProcess Win 32中大概有100個其他的函數用于處理進程的管理,同步以及相關的事務。下面是UNIX操作系統和 Windows操作系統系統調用的對比
-
在UNIX和Windows中,進程創建之后,父進程和子進程有各自不同的地址空間。如果其中某個進程 在其地址空間中修改了一個詞,這個修改將對另一個進程不可見。
-
在UNIX中,子進程的地址空間是父 進程的一個拷貝,但是確是兩個不同的地址空間;不可寫的內存區域是共享的。
-
某些UNIX實現是正是 在兩者之間共享,因為它不能被修改。
-
或者,子進程共享父進程的所有內存,但是這種情況下內存通過寫時復制(copy-on-write)共享,這意味著一旦兩者之一想要修改部分內存,則這塊內存首先被明確 的復制,以確保修改發生在私有內存區域。
-
再次強調,可寫的內存是不能被共享的。但是,對于一個新 創建的進程來說,確實有可能共享創建者的資源,比如可以共享打開的文件。
-
在Windows中,從一開 始父進程的地址空間和子進程的地址空間就是不同的。
進程的終止
-
進程在創建之后,它就開始運行并做完成任務。然而,沒有什么事兒是永不停歇的,包括進程也一樣。進程早晚會發生終止,但是通常是由于以下情況觸發的
-
?正常退出(自愿的)
-
? 錯誤退出(自愿的)
-
?嚴重錯誤(非自愿的)
-
?被其他進程殺死(非自愿的)
-
正常退出
-
多數進程是由于完成了工作而終止。當編譯器完成了所給定程序的編譯之后,編譯器會執行一個系統調 用告訴操作系統它完成了工作。這個調用在UNIX中是exit ,在Windows中是ExitProcess。
-
面向屏幕中的軟件也支持自愿終止操作。字處理軟件、Internet瀏覽器和類似的程序中總有一個供用戶 點擊的圖標或菜單項,用來通知進程刪除它鎖打開的任何臨時文件,然后終止。
-
錯誤退出
-
進程發生終止的第二個原因是發現嚴重錯誤,例如,如果用戶執行如下命令
-
為了能夠編譯foo.c但是該文件不存在,于是編譯器就會發出聲明并退出。
-
在給出了錯誤參數時,面向 屏幕的交互式進程通常并不會直接退出,因為這從用戶的角度來說并不合理,用戶需要知道發生了什么 并想要進行重試,所以這時候應用程序通常會彈出一個對話框告知用戶發生了系統錯誤,是需要重試還 是退出。
-
嚴重錯誤
-
進程終止的第三個原因是由進程引起的錯誤,通常是由于程序中的錯誤所導致的。
-
例如,執行了一條非 法指令,引用不存在的內存,或者除數是0等。在有些系統比如UNIX中,進程可以通知操作系統,它 希望自行處理某種類型的錯誤,在這類錯誤中,進程會收到信號(中斷),而不是在這類錯誤出現時直 接終止進程。
-
被其他進程殺死
-
第四個終止進程的原因是,某個進程執行系統調用告訴操作系統殺死某個進程。在UNIX中,這個系統 調用是kill。在Win32中對應的函數是TerminateProcess (注意不是系統調用)。
進程的層次結構
-
在一些系統中,當一個進程創建了其他進程后,父進程和子進程就會以某種方式進行關聯。子進程它自己就會創建更多進程,從而形成一個進程層次結構。
-
UNIX進程體系
-
在UNIX中,進程和它的所有子進程以及子進程的子進程共同組成一個進程組。當用戶從鍵盤中發出一 個信號后,該信號被發送給當前與鍵盤相關的進程組中的所有成員(它們通常是在當前窗口創建的所有 活動進程)。每個進程可以分別捕獲該信號、忽略該信號或采取默認的動作,即被信號kill掉。
這里有另一個例子,可以用來說明層次的作用,考慮UNIX在啟動時如何初始化自己:
-
一個稱為init的特殊進程出現在啟動映像中。當init進程開始運行時,它會讀取一個文件,文件會告訴它有 多少個終端。
-
然后為每個終端創建一個新進程。這些進程等待用戶登錄。如果登錄成功,該登錄進程就 執行一個shell來等待接收用戶輸入指令,這些命令可能會啟動更多的進程,以此類推。
-
因此,整個操 作系統中所有的進程都隸屬于一個單個以init為根的進程樹。
-
Windows進程體系
-
相反,Windows中沒有進程層次的概念,Windows中所有進程都是平等的
-
唯一類似于層次結構的是 在創建進程的時候,父進程得到一個特別的令牌(稱為句柄),該句柄可以用來控制子進程。
-
然而,這 個令牌可能也會移交給別的操作系統,這樣就不存在層次結構了。而在UNIX中,進程不能剝奪其子進 程的 進程權。(這樣看來,還是Windows比較渣)。
進程狀態
- 盡管每個進程是一個獨立的實體,有其自己的程序計數器和內部狀態,但是,進程之間仍然需要相互幫 助。例如,一個進程的結果可以作為另一個進程的輸入,在shell命令中
- 第一個進程是cat ,將三個文件級聯并輸出。
- 第二個進程是grep ,它從輸入中選擇具有包含關鍵字 tree的內容,根據這兩個進程的相對速度(這取決于兩個程序的相對復雜度和各自所分配到的CPU 時間片),可能會發生下面這種情況
- grep準備就緒開始運行,但是輸入進程還沒有完成,于是必 須阻塞grep進程,直到輸入完畢。
當一個進程開始運行時,它可能會經歷下面這幾種狀態:
-
圖中會涉及三種狀態
-
1.運行態,運行態指的就是進程實際占用CPU時間片運行時
-
2.就緒態,就緒態指的是可運行,但因為其他進程正在運行而處于就緒狀態
-
3.阻塞態,除非某種外部事件發生,否則進程不能運行
-
邏輯上來說,運行態和就緒態是很相似的。這兩種情況下都表示進程可運行,但是第二種情況沒有獲得CPU時間分片。第三種狀態與前兩種狀態不同的原因是這個進程不能運行,CPU空閑時也不能運 行。
-
三種狀態會涉及四種狀態間的切換,在操作系統發現進程不能繼續執行時會發生狀態1的輪轉,在某些 系統中進程執行系統調用
- 例如pause ,來獲取一個阻塞的狀態。在其他系統中包括UNIX,當進程
從管道或特殊文件(例如終端)中讀取沒有可用的輸入時,該進程會被自動終止。
- 轉換2和轉換3都是由進程調度程序(操作系統的一部分)引起的,進程本身不知道調度程序的存 在。
- 轉換2的出現說明進程調度器認定當前進程已經運行了足夠長的時間,是時候讓其他進程運行 CPU時間片了。
- 當所有其他進程都運行過后,這時候該是讓第一個進程重新獲得CPU時間片的時候 了,就會發生轉換3。
- 程序調度指的是,決定哪個進程優先被運行和運行多久,這是很重要的一點。已經設計出許多算 法來嘗試平衡系統整體效率與各個流程之間的競爭需求。
-
當進程等待的一個外部事件發生時(如從外部輸入一些數據后),則發生轉換4。
-
如果此時沒有其他進 程在運行,則立刻觸發轉換3,該進程便開始運行,否則該進程會處于就緒階段,等待CPU空閑后再 輪到它運行。
從上面的觀點引入了下面的模型
- 基于進程的操作系統中最底層的是中斷和調度處理,在該層之上是順序進程
操作系統最底層的就是調度程序,在它上面有許多進程。
所有關于中斷處理、啟動進程和停止進程的具 體細節都隱藏在調度程序中。事實上,調度程序只是一段非常小的程序。
進程的實現
- 操作系統為了執行進程間的切換,會維護著一張表格,這張表就是進程表(process table)。每個進 程占用一個進程表項。該表項包含了進程狀態的重要信息,包括程序計數器、堆棧指針、內存分配狀 況、所打開文件的狀態、賬號和調度信息,以及其他在進程由運行態轉換到就緒態或阻塞態時所必須保 存的信息,從而保證該進程隨后能再次啟動,就像從未被中斷過一樣。
下面展示了一個典型系統中的關鍵字段
-
第一列內容與進程管理有關,第二列內容與 存儲管理有關,第三列內容與文件管理有關。
-
現在我們應該對進程表有個大致的了解了,就可以在對單個CPU上如何運行多個順序進程的錯覺做更 多的解釋。
-
與每一 I/O類相關聯的是一個稱作 中斷向量(interrupt vector)的位置(靠近內存底部 的固定區域)。它包含中斷服務程序的入口地址。
-
假設當一個磁盤中斷發生時,用戶進程3正在運行, 則中斷硬件將程序計數器、程序狀態字、有時還有一個或多個寄存器壓入堆棧,計算機隨即跳轉到中斷 向量所指示的地址。這就是硬件所做的事情。然后軟件就隨即接管一切剩余的工作。
-
當中斷結束后,操作系統會調用一個C程序來處理中斷剩下的工作。在完成剩下的工作后,會使某些進 程就緒,接著調用調度程序,決定隨后運行哪個進程。
-
然后將控制權轉移給一段匯編語言代碼,為當前 的進程裝入寄存器值以及內存映射并啟動該進程運行
下面顯示了中斷處理和調度的過程:
- 1.硬件壓入堆棧程序計數器等
- 2.硬件從中斷向量裝入新的程序計數器
- 3.匯編語言過程保存寄存器的值
- 4.匯編語言過程設置新的堆棧
- 5.C中斷服務器運行(典型的讀和緩存寫入)
- 6.調度器決定下面哪個程序先運行
- 7.C過程返回至匯編代碼
- 8.匯編語言過程開始運行新的當前進程
- 一個進程在執行過程中可能被中斷數千次,但關鍵每次中斷后,被中斷的進程都返回到與中斷發生前完 全相同的狀態。
總結
以上是生活随笔為你收集整理的OS- -进程详详解的全部內容,希望文章能夠幫你解決所遇到的問題。