1. 程式人生 > >現代作業系統之程序與執行緒(上)

現代作業系統之程序與執行緒(上)

程序

基本概念

一個程序就是一個正在執行程式的例項,包括程式計數器、暫存器和變數當前的值。從概念上說,每個程序擁有它自己的虛擬cpu。實際上,每個瞬間CPU只能執行一個程序。 在對程序程式設計時不能對時序做任何確定對假設。


建立程序

常見情況:
  1. 系統初始化
  2. 執行政治執行對程序所呼叫的程序建立系統呼叫
  3. 使用者請求建立一個新程序
  4. 一個批處理作業的初始化
在任務可以輕易劃分成若干相關但沒有相互作用但程序時,建立新程序就特別有效果 從技術上看,所有新程序都是由一個已存在但程序執行了一個用於建立程序但系統呼叫而建立的,並且直接或間接指導該程序中執行的程式。 在UNIX系統中,只有fork可以用來建立新程序
UNIX中,紫禁城的初始地址時副程序的一個副本,但是涉及兩個不同的地址空間,不可洩記憶體去時共享的。所以對於新程序時可能共享建立者的其它資源。而windows中父子程序地址從開始就不同

程序終止

程序推出由一下條件引起:
  1. 正常推出(自願)
  2. 出錯退出(自願)
  3. 嚴重錯誤(非自願)
  4. 被其他程序殺死(非自願)
在殺死其他程序中需要確定授權才可以(UNIX中為kill,WIN32中為TerminateProcess)

程序的層次

在UNIX中,程序和它所有子女即後裔足層一個晉城組,訊號將被髮送到相關程序詛的所有成員。每個程序都以分別捕獲、忽略或採取預設行動(被該訊號殺死) win32中所有程序地位相同,唯一的不同在於父程序會獲得一個控制代碼(可轉讓)。 UNIX程序不能剝奪其子程序的繼承權

程序的狀態

程序狀態由三種——執行態、就緒態和阻塞態。 阻塞態不能執行,就算是CPU空閒也不能執行。 作業系統最底層是排程程式。

程序的實現

作業系統維護一張程序表(結構陣列),表中儲存程序資訊。 終端硬體將程式計數器、程式狀態字、有時還有一個或多個暫存器雅茹對戰,計算機隨即跳轉到中斷向量所指示的地址。

多道程式設計模型

假設一個程序等待IO操作的時間預期停留在記憶體中的時間比為p,當記憶體中同時由n個程序時,則所有n個程序都在等待IO的概率為p的n次方,所以CPU利用率為1-P的n次方。

執行緒

執行緒是輕量級的程序,代價更小,切換速度更快,還可以共享變數。 一種組織伺服器的模型是允許把伺服器編寫為一個順序執行緒的集合。在分派執行緒的程式中包含以後 一個無限迴圈,改虛幻用來獲得工作請求並將工作請求分派給工作執行緒。每個工作執行緒會從阻塞到就緒,處理完成後再次變為阻塞。 多程序是的順序程序的思想被保留下來,這種順序程序阻塞了系統呼叫,但仍舊實現但並行性。而單執行緒雖然保留了阻塞系統呼叫的簡易性,但是放棄了效能。非同步運用了非阻塞和中國年的伏安,通過並行性實現了高效能,但是給程式設計增加了困難。


經典執行緒模型

程序用於把資源集中到一起,而執行緒則是在CPU上被排程執行的實體。 同一個程序中的多個執行緒,是對同一臺計算機上並行執行多個程序的模擬。前者多執行緒共享同一個地址空間和其它資源。而在後一種情形中,多個程序共享實體記憶體,磁碟等資源。 執行緒概念試圖實現的是共享一組資源的多個執行緒的執行能力,以便這些執行緒可以為完成某一個任務共同 工作。 和程序一樣,執行緒有四種狀態——執行,阻塞、就緒或終止。 每個執行緒都有自己的堆疊,其中存放一些響應過程的區域性變數還有完成之後使用的返回地址。 在多執行緒情況下,程序通常會從當前的單個執行緒開始。不論有無層次關係,建立執行緒通常都返回一個執行緒識別符號,該識別符號就是新執行緒的名字。 一個執行緒可以等待一個(特定)的執行緒推出,這個過程阻塞呼叫指導那個特定執行緒退出。 不同於程序,(執行緒庫無法利用始終強制終端執行緒讓出CPU。)

POSIX執行緒

Prhtead是IEEE定義的執行緒標準 每一個都有一個識別符號,一組暫存器(包括程式計數器)和一組儲存在結構中的屬性。



使用者執行緒

整個執行緒報放在使用者空間中,核心對執行緒包一無所知。 使用者及執行緒包可以在不支援執行緒對作業系統上實現。 在使用者空間管理執行緒時,每個程序需要有其專業的執行緒包,用來跟中國年該執行緒表中的執行緒。這些表和核心中國年的程序表類似,不過它僅僅記錄各個執行緒的屬性。 當一個執行緒轉換到就緒狀態或阻塞狀態時,在該縣城表中存放重新啟動該執行緒所需的資訊。 只要堆疊指標和程式計數器一切換,新的執行緒就自動投入執行。 進行類似與這樣的執行緒切換至少要比陷入核心快一個數量級,這也是使用者及執行緒包的優點。 使用者級執行緒的另一個有點是允許每個程序自己訂製的排程演算法,而且還具有很好的擴充套件性。(核心執行緒需要一些固定的表格空間和對戰空間,如果核心級執行緒過多會出問題) 使用者級執行緒確定也很多:
  1. 如何實現阻塞系統呼叫。
  2. 如果一個執行緒引起也沒故障,核心由於甚至不知道有執行緒存在,通常會把整個程序阻塞指導磁碟IO完成未知,儘管其它執行緒可以允許
  3. 如果一個執行緒開始允許,則該程序中的其他執行緒不可允許,除非第一個執行緒自動放棄cpu。

核心執行緒

核心執行緒不再需要執行時系統,每個程序中也沒有執行緒表,執行緒表處於核心中。當建立或銷燬執行緒時,會出發系統呼叫, 執行緒表可以說是傳統程序表的子集。 所有能夠阻塞執行緒的呼叫都以系統呼叫的形式實現,這雨執行時系統過程相比,代價相當可觀。而當一個執行緒阻塞時,核心根據其選擇,可以允許同一個程序中的另一個執行緒。 訊號是發給程序而不是執行緒的,執行緒可以註冊它感興趣的訊號。

排程程式啟用機制

儘管核心級執行緒在一些關鍵點上由於使用者級執行緒,但是核心級執行緒較慢。 (回頭複習)

彈出式執行緒

一個訊息到來導致系統建立一個處理該訊息的執行緒,則稱為但出事執行緒。其好處在於執行緒沒有歷史,所有新執行緒都一樣,因此可以快速建立,而對於訊息來說,訊息到達與處理開始直接的時間非常短。 在使用彈出式執行緒之前,需要提前計劃。在核心級空間允許彈出式執行緒通常比在使用者空間容易且快捷,但是一旦出錯危害更大。

使用單執行緒程式碼多執行緒化

對於執行緒是全域性變數,並不意味著對於程序同樣是全域性變數。 有時候執行緒會有私有的全域性變數,就算不同執行緒宣告的同一個變數也是兩個獨立的變數。 將單一執行緒程式轉化為多執行緒存在一個問題——很多庫不可重複載入。 類似的情況還有記憶體分派。 一種解決方案是設定二進位制位來標誌是否在使用,如果存在使用則阻塞。 多執行緒的另一個問題是堆疊,由核心不瞭解所有堆疊,則可能導致執行緒堆報錯。 綜上,改寫程式時不進行重新設計是不可能的。