進程與線程

2.1 進程與線程

  操作系統越複雜,期望它能夠爲用戶做的事情越多。雖然它主要關注用戶程序的執行,但是也需要處理內核自身之外的各種系統任務。系統由進程集合組成:操作系統進程執行系統代碼,用戶進程執行用戶代碼。通過CPU在進程間多路複用,所有這些進程潛在地能夠並行執行。通過在進程間轉換CPU,操作系統可以使計算機獲得更好的性能。

2.1.1 進程概念及特徵

  1.進程的概念
  進程(Process)這個術語最早是1960 年在MIT 的MULTICS 和IBM 公司的TSS/360系統中提出來的,直到目前對進程的定義和名稱還尚不統一,不同的系統採用不同的術語名稱,如MIT稱進程(Process),IBM公司稱任務(Task),Univac 公司稱活動(Active)。因此,進程的定義有很多種。
  這裏較能反映進程實質的定義如下。
  進程是程序的一次執行。
  進程是可以和別的計算機併發執行的計算。
  進程可定義爲一個數據結構,以及能在其上進行操作的一個程序。
  進程是一個程序及其數據在處理機上順序執行時所發生的活動。
  進程是程序在一個數據集合上運行的過程,它是系統進行資源分配和調度的一個獨立單位。
  需要注意的是,雖然兩個進程與同一個程序相關,但是它們被當作兩個獨立的執行序列,雖然文本段相同,但是數據段不同。總之,進程的概念可以這樣理解,進程是一個可併發執行的具有獨立功能的程序關於某個數據集合的一次執行過程,也是操作系統進行資源分配和保護的基本單位。
  2.進程的特徵
  進程併發執行時,與順序程序的特徵完全不同,它破壞了順序程序的封閉性和可再現性。表現在它具有以下特徵。
  動態性:進程是進程實體的執行過程。因此,動態性是進程最基本的特徵。進程具有一定的生命週期,即進程由創建而產生,由調度而執行,因得不到資源而暫停執行,以及由撤銷而消亡。
  併發性:多進程同時存在於內存中,在一段時間內同時運行。
  獨立性:未建立進程的程序,都不能作爲一個獨立的單元運行。
  異步性:進程按各自獨立的、不可預知的速度向前推進,導致程序具有不可再現性。因此,在操作系統中,必須採取某種措施來保證各程序之間能協調運行。
  結構特徵:由程序(段)、數據(段)和進程控制塊組成。
  3.進程的組成及與程序之間的聯繫與區別
  從進程的定義和結構來看,進程由程序、數據和進程控制塊三部分組成。程序和數據是進程完成指定功能所必需的運行實體,而進程控制塊是進程存在的唯一標識,是系統對進程進行管理和控制的實體。
  進程是程序的一次執行過程,沒有程序就沒有進程。程序是完成某個特定功能的一系列程序語句的集合,只要不被破壞,它就永遠存在。程序是一個靜態的概念,而進程是一個動態的概念,它由創建而產生,完成任務後因撤銷而消亡;進程是系統進行資源分配和調度的獨立單位,而程序不是。
  4.引入進程的利弊
  引入進程是基於多道程序和分時系統的需要,因爲只有爲每道程序建立了進程,它們才能併發執行。通過進程的併發執行,來改善系統的資源利用率和提高系統的吞吐量。因此目前大多數系統幾乎都引入了進程,但系統也爲此付出了下述開銷:
  空間開銷:系統必須爲每個進程建立進程控制塊(PCB),它通常要佔用幾十到幾百個內存單元;此外,爲了協調各進程的併發執行,系統還必須設置相應的進程管理機構,這也必然佔用可觀的內存空間;
  時間開銷:爲了協調各進程的運行,也必須付出時間開銷;例如,在進行進程切換時,系統必須保證存在運行進程的現場,爲即將運行的線程設置新現場,這都需要花費CPU時間。

 

2.1.2 進程的狀態與轉換

  在操作系統中,進程在不同的階段有不同的狀態,而且各種狀態之間是可以轉換的。下面將介紹進程的各種狀態及狀態的轉換。
  1.進程的基本狀態
  一個進程從創建而產生至撤銷而消亡的整個生命期間,有時佔有處理器執行,有時雖可運行但分不到處理器、有時雖有空閒處理器但因等待某個事件的發生而無法執行,這一切都說明進程和程序不相同,它是活動的且有狀態變化的,這可以用一組狀態加以刻畫。爲了便於管理進程,按進程在執行過程中的不同情況,可將進程分爲以下幾種基本狀態。
  執行狀態(Running):進程佔用處理機正在執行其程序。單處理機系統中只能有一個進程處於執行狀態,多處理機系統中可能有多個進程處於執行狀態。
  阻塞狀態(Blocked):也叫等待或睡眠狀態,是進程由於等待某種事件的發生而處於暫停執行的狀態。如進程因等待I/O的完成、等待緩衝空間等。
  就緒狀態(Ready):進程已分配到除處理機以外的所有必要資源,具備了執行的條件,可能會有多個進程處於就緒狀態,排成就緒隊列。
  2.新狀態和終止狀態
  新狀態:進程剛剛建立,還沒有送入就緒隊列的狀態。
  終止狀態:一個進程已正常結束或非正常結束,操作系統已將它從就緒隊列中移出,尚未將它撤銷時的狀態。
  3.進程狀態的轉換
  進程在執行期間,可以多次處於就緒狀態和執行狀態,也可以多次處於阻塞狀態,但處於新狀態只有一次。圖2-1顯示了各種狀態之間的轉換流程,狀態之間的轉換大體包含如下幾種。

  新狀態到就緒狀態:當就緒隊列允許接納新進程時,系統便把處於新狀態進程移入就緒隊列。
  就緒狀態到執行狀態:進程調度程序爲處於就緒狀態的進程分配處理機後,該進程進入執行狀態。
  執行狀態到阻塞狀態:正在執行的進程因需要等待某事件而無法執行,讓出處理機。
  阻塞狀態到就緒狀態:進程所等待的事件發生了,進程就從阻塞狀態進入就緒狀態。
  執行狀態到就緒狀態:正在執行的進程因時間片用完而被暫停執行;或者在可搶佔調度方式中,一個優先權高的進程到來後,正在執行的優先權低的進程被強制撤下處理機,轉換爲就緒狀態。
  執行狀態到終止狀態:一個進程已完成或發生某種特殊事件,進程將變爲終止狀態。

 

2.1.3 進程控制

  進程控制的內容主要包括進程控制機構、進程的創建、進程的終止等內容,下面我們分別介紹這些內容。
  1.進程控制機構
  操作系統作爲資源管理和分配程序,其本質任務是自動控制程序的執行,並滿足進程執行過程中提出的資源使用要求。因此,操作系統的核心控制結構是進程結構,資源管理的數據結構將圍繞進程結構展開。
  操作系統使用系統原語控制進程狀態改變,原語被認爲是機器語言的延伸,是完成特定任務的一段基本程序,它具有原子操作性。原子操作是不可分的操作,要麼全做,要麼全不做,它是通過中斷屏蔽來實現的。原語對用戶是透明的,一般不允許直接使用,但是允許程序員作爲一種特殊的系統調用來使用。
  操作系統的控制表分爲四類:進程控制表,存儲控制表,I/O 控制表和文件控制表。
  進程控制表用來管理進程及其相關信息。
  存儲控制表用來管理一級(主)存儲器和二級(輔)存儲器,主要內容包括:主存儲器的分配信息,二級存儲器的分配信息,存儲保護和分區共享信息,虛擬存儲器管理信息。
  I/O控制表用來管理計算機系統的I/O 設備和通道,主要內容包括:I/O 設備和通道是否可用,I/O設備和通道的分配信息,I/O 操作的狀態和進展,I/O 操作傳輸數據所在的主存區。
  文件控制表用來管理文件,主要內容包括:被打開文件的信息,文件在主存儲器和二級存儲器中的位置信息,被打開文件的狀態和其他屬性信息。
  2.主要進程原語
  (1)創建原語(Create)
  進程創建的方式有兩種:一是由系統程序模塊統一創建,二是由父進程創建。它們都需要調用創建原語來實現。創建原語的主要工作是,首先掃描系統的PCB表,查詢有無空的PCB表項,如有,則申請一個,並對其進程初始化,初始化的項目有進程標識符(PID)、進程狀態和執行程序的起始地址;如果申請不成功,則創建失敗。
  進程的創建過程描述如下。
  在主進程表中增加一項,並從PCB 池中申請一個空白PCB。
  爲新進程的進程映像分配地址空間。對於進程創建操作還需要傳遞環境變量,構造共享地址空間。
  爲新進程分配資源,除內存空間外,還有其他各種資源。
  查找輔助存儲器,找到進程正文段並裝入到進程地址空間的正文區。
  初始化進程控制塊(如狀態、PSW、棧等),爲新進程分配一個唯一的進程標識符。
  把進程加入某一就緒進程隊列(這時子進程就緒),或直接將進程投入運行(這時父進程就緒)。
  通知操作系統的某些模塊,如記賬程序、性能監控程序。
  (2)撤銷原語(Kill)
  當進程正常執行完畢後,或者由於某種錯誤非正常終止時,都需要調用撤銷原語來釋放該進程所佔用的各種資源和PCB結構本身,以利於有效地使用資源。撤銷原語的主要工作是,首先檢查PCB鏈表,尋找所要撤銷的進程是否存在。如果找到了相應的表項,撤銷原語就釋放該進程佔用的資源並回收對應的PCB結構;如果被撤銷的進程還有子進程,則撤銷原語必須先撤銷子進程的  PCB並釋放其所佔用的資源。
  進程撤銷的具體步驟如下。
  根據撤銷進程標識號,從相應隊列中找到它的PCB。
  將該進程擁有的資源歸還給父進程或操作系統。
  若該進程擁有子進程,應先撤銷它的所有的子孫進程,以防它們脫離控制。
  撤銷進程出隊,將它的PCB 歸還到PCB 池。
  (3)阻塞原語(Block)
  當進程等待某些事件(如讀寫磁盤、接受其他進程的數據)的產生時,通過執行阻塞原語來阻塞自己。阻塞原語在執行時,必須先中斷處理機並同時保存該進程的CPU現場。然後將阻塞進程插入到等待隊列中,再轉由調度程序從就緒隊列中選擇一個進程投入運行。進程阻塞的步驟如下。
  停止進程執行,保存現場信息到PCB。
  修改進程控制塊的有關內容,如進程狀態由運行改爲等待等。
  把修改狀態後的進程控制塊加入相應等待進程隊列。
  接着便應轉入進程調度程序去調度其他進程運行。
  (4)喚醒原語(Wakeup)
  又稱爲恢復原語,當進程等待的條件或事件產生後,等待該事件的所有進程都被喚醒。喚醒進程的方法有兩種:一種是系統進程喚醒;另一種是由事件發生進程喚醒。它們都需要調用喚醒原語來喚醒另一進程。喚醒原語首先將被喚醒進程從相應的等待隊列取下,並將其狀態設置爲就緒態後,送入就緒隊列。此時,喚醒原語既可以從調用程序處直接返回,也可以轉向進程調度程序,讓調度程序選擇一個合適的進程去執行。需要注意的是,一個進程由執行狀態轉變爲阻塞狀態,是這個進程自己調用阻塞原語去完成的;而進程由阻塞狀態到就緒狀態,是另一個發現者進程調用喚醒原語實現的,一般這個發現者進程與被喚醒進程是合作的併發進程。進程喚醒的步驟如下。
  從相應的等待進程隊列中取出進程控制塊。
  修改進程控制塊的有關信息,如進程狀態改爲就緒。
  把修改後的進程控制塊加入有關就緒進程隊列。
  (5)掛起原語(Suspend)
  當用戶或創建者需要了解進程的活動情況或干預進程活動時,可以把某進程置於掛起就緒狀態或掛起阻塞狀態,這時,要調用掛起原語,掛起方式如下。
  發命令進程自身掛起。
  掛起具有制定標識符的進程。
  將某進程及其全部或部分子進程掛起。
  (6)激活原語(Active)
  激活原語使處於靜止狀態的進程變爲活動狀態,即供用戶或創建者重新激活已掛起的進程,激活方式有多種,如激活一個指定標識符的進程,或激活某進程及其所有子進程等。當激活後的進程處於活動就緒狀態時,將引起重新調度。
  進程在系統中能夠並行執行,並且它們必須要動態地創建和刪除。因此,操作系統必須提供進程創建和終止的機制(或方法)。
  3.進程的創建
  進程在運行期間,通過創建進程系統調用可以創建多個新進程。創建進程的進程被稱爲父進程,而新進程被稱爲子進程。每個新進程都可以創建另外的進程,從而形成一個進程樹。
  每一個進程都有生命期,即從創建到消亡的時間週期。當操作系統爲一個程序構造一個進程控制塊並分配地址空間之後,就創建了一個進程。進程的創建來源於以下四個事件。
  提交一個批處理作業。
  在終端上一個交互式作業登錄。
  操作系統創建一個服務進程。
  存在的進程創建新的進程。
  4.進程的終止
  進程執行完最後一條語句後就終止執行,並調用exit系統調用來使操作系統刪除它。在此,該進程可能要把數據(輸出)返回給它的父進程(通過wait系統調用)。操作系統回收該進程的所有資源——包括物理和虛擬內存、打開文件和I/O 緩衝器。
  進程也可能在其他的情況下終止運行。一個進程可以利用系統調用(例如:abort)終止其他的進程。通常,只有進程的父進程可以調用這樣的系統調用來終止它。否則,用戶可以任意地取消其他用戶的作業。所以父進程需要知道其子進程的標識符。如此,當一個進程創建一個新進程時,新創建的進程的標識符要傳給其父進程。
  父進程可能會出於某種原因而結束它的一個子進程,例如:
  子進程需要更多的資源。這需要父進程能夠檢查其子進程的狀態;
  分配給子進程的任務已經不再需要;
  父進程退出,而且操作系統禁止子進程在父進程終止後繼續執行。在這樣的系統中,如果一個進程(正常或非正常)終止,那麼它的所有子進程也必須終止。通常這種級聯式的進程終止是操作系統發起的。

2.1.4 進程組織

  進程組織是指進程的組織方式,下面從進程實體和進程控制塊兩個方面來了解進程的組織結構。
  1.進程實體
  在操作系統中,一個進程是通過其物理實體被感知的,進程的物理實體又稱爲進程的靜態描述。進程的靜態描述通常由三部分組成:程序、數據集合、進程控制塊(PCB)。
  程序:描述進程所要完成的功能。
  數據集合:程序運行所需要的數據部分和工作區。
  進程控制塊:包含了進程的描述信息、控制信息和資源信息,是進程動態特性的集中反映。
  程序是產生進程的基礎,通過進程產生進程。如果一個程序能爲多個進程同時共享執行,那麼這部分就以純碼,也就是再入碼形式編制,它是進程執行時不可修改的部分。數據集合通常爲一個進程獨佔,爲進程的可修改部分。程序和數據集合是進程存在的物質基礎,是進程的實體。進程控制塊是進程存在的標誌,進程與進程控制塊是一對一的關係,進程控制塊記錄進程的控制信息和描述信息,操作系統利用進程控制塊對併發執行的進程進行控制和管理,進程控制塊是操作系統中最重要的記錄行數據結構。
  2.進程控制塊(PCB)
  PCB是保存進程的狀態和控制進程轉換的標識,也是進程存在的唯一標識。創建進程則產生PCB,撤銷進程系統就要回收PCB。圖2-2給出了一個PCB的例子,PCB主要包括描述信息、管理信息、資源清單、現場保護區和其他功能。操作系統通過PCB表(或隊列)來管理與控制進程。PCB表項的個數是確定的,所以也就限制了系統中進程的個數不能超過某個值。

  (1)進程描述信息
  進程標識符:標識各個進程,每個進程都有一個並且是唯一的標識名或標識號。
  用戶標識符:每個進程屬於某個用戶,用戶標識符主要爲共享和保護服務。
  (2)進程控制信息
  進程當前狀態:作爲調度程序分配處理機的依據。當進程處於阻塞狀態時,要在PCB中說明阻塞原因。
  進程優先級:表示進程使用CPU時優先級別的一個整數。優先級高的進程可優先獲得處理機。
  代碼執行入口地址。
  程序的外存地址:進程執行程序的地址。
  各種計時信息:給出進程執行時間、頁面調度情況。
  通信信息:用來說明該進程與其他進程的信息交換情況,如進程同步、阻塞原因等。
  (3)資源管理信息
  用於說明有關虛擬地址空間的現狀、打開文件列表和使用的輸入/輸出設備信息。
  (4)CPU現場保護結構
  CPU現場保護結構保存寄存器值,如通用寄存器、程序計數器PC、狀態PSW、地址包括棧指針的值等。
  在系統中PCB數目較多,應該採用合適的方式,將它們組織起來,進行有效的管理。目前常用的組織方式有鏈接方式和索引方式兩種。
  鏈接方式
  把具有相同狀態的PCB,用其中的鏈接字,鏈接成一個隊列。這樣可形成就緒隊列、阻塞隊列等。對其中的就緒隊列按進程的優先權排列,把優先權高的PCB排在前面。另外,也可根據阻塞原因把阻塞狀態進程的PCB排成等待I/O操作完成、等待分配內存等隊列。
  索引方式
  根據所有進程的狀態,建立幾張索引表,如就緒索引表、阻塞索引表等。並把各索引表在內存的首地址記錄在內存中的一些專用單元。在每個索引表的表目中,記錄具有相應狀態的某個PCB在PCB表中的地址。

 

2.1.5 進程通信

  進程間的信息交換稱爲進程通信,進程之間的互斥與同步就是兩種進程通信方式。由於進程互斥與同步交換的信息量較少,每次通信傳遞的信息量固定且效率較低,因此稱這兩種通信方式爲低級通信方式;相應地,也可將P、V操作稱爲兩條低級通信原語。所謂高級通信方式是指進程之間以較高的效率傳送大量數據的通信方式。
  高級通信方式可分爲三大類:共享存儲器系統、消息傳遞系統以及管道通信系統。
  1.共享存儲器系統
  在這種方式中,相互通信的進程共享某些數據結構或共享存儲區,具體可分爲以下兩種方式:
  一種是高級通信方式的共享存儲區:是指進程之間通過對共享存儲區的讀/寫,來交換數據;
  另一種方式是利用共享的數據結構來進行進程通信,進程之間通過某種類型的數據結構來交換信息,如生產者-消費者問題,便是利用有界緩衝區這種數據結構來進行通信的。但這種方式對共享數據結構的設置及對進程間的同步,都必須由程序員來處理,且只能進行少量的數據交換,因此,屬於低級通信方式。
  2.消息傳遞系統
  在消息傳遞系統中,消息系統的功能是允許進程與其他的進程進行通信而不必藉助共享數據,進程間的數據交換以格式化的消息(報文)爲單位。根據實現方式的不同,它又可分爲直接通信和間接通信兩類。
  在直接通信方式中,源進程可直接將消息發送給目標進程,此類操作系統通常提供send(receiver, message)和receive(sender,message)兩條通信命令(原語)供用戶使用。
  在間接通信方式中,進程間需要通過某種中間實體(即信箱)來進行通信。發送進程將消息投入信箱,而接受進程則從信箱中取得消息。因此,它不僅能實現實時通信,還能實現非實時通信。此時,操作系統應提供若干條原語,分別用於信箱的創建、撤銷和消息的發送、接收等。
  如果進程P 和Q 要進行通信,那麼它們必須能夠互相發送和接收消息;兩者之間必須要建立一條通信鏈路。有多種方法可以實現這條鏈路。在這裏,我們並不關心鏈路的物理實現,而是要考慮它的邏輯實現。有如下幾種用於邏輯實現和send/receive 操作的方法:
  直接或間接通信;
  對稱或不對稱通信;
  自動或手動緩衝;
  發送複製或引用;
  定長消息或變長消息。
  (1)直接通信
  直接通信中,需要通信的每個進程都必須直接指明通信的接收方或發送方。在這種方式下,發送和接收原語定義如下:
  send(P,message)——發送一個消息給進程P;
  receive(Q,message)——從進程Q中接收一個消息。
  這種通信鏈路具有如下特點:
  每對需要通信的進程之間自動地建立一條鏈路。進程只需要知道彼此的標識符;
  一個連接就只連接到這兩個進程;
  每對進程間只能建立一條鏈路。
  這種機制在尋址上對稱。發送者和接收者進程都必須要指明通信的另一方。這種機制的一個變種在尋址上採用了不對稱的方式。只需發送者指明接收者;而接收者不需要指明發送者。在這種方式下,發送和接收原語定義如下:
  send(P,message)——發送一個消息給進程P;
  receive(id,message)——從任意進程中接收一個消息;變量id 被聯繫到與之通信的進程的名稱。
  對稱和不對稱機制的缺點在於它限制了進程定義的模塊化程度。更改一個進程的名稱可能必須要檢查其他所有進程的定義。必須要發現所有對原名稱的引用,以便於更換爲新名稱。從獨立編譯角度來看,這種情形可不是希望看到的。
  (2)間接通信
  間接通信中,消息的發送和接收通過信箱(或端口)進行。可以抽象地把信箱看成一個對象,進程可以把消息放置其中也能從中取走。每個信箱都有一個唯一的標識符。在這種方式下,進程可以通過不同的信箱與其他進程通信。兩個進程只有共享一個信箱纔可以進行通信。發送和接收原語定義如下:
  send(A,message)——向信箱A中發送一個消息;
  receive(A,message)——從信箱A中接收一個消息。
  這種通信鏈路具有如下特點:
  只有在兩個進程間有一個共享信箱的情況下才能在兩者之間建立一個鏈接;
  一條鏈路可以連接兩個或更多進程;
  在每對通信進程之間可以同時存在多個不同的鏈路,每條鏈路對應一個信箱。
  假設進程P1、P2和P3 共享信箱A,而且P2 和P3 正從A 中接收。那麼誰將接收到P1 發送的消息呢?答案與我們選擇的方案有關:
  允許一條鏈路最多連接兩個進程;
  同時最多允許一個進程執行接收操作;
  允許系統任意選擇進程來接收消息[就是說,P2 或者P3(但不能都是)將接收消息]。系統可能會確定接收者。
  一個信箱可能爲一個進程或操作系統所有。如果信箱的所有者是一個進程(也就是說,此信箱佔據了該進程的部分地址空間),那麼就要區分所有者(唯一可以從這個信箱中接收消息)和用戶(只能夠向這個信箱中發送消息)。因爲每個信箱有一個唯一的所有者,所以誰可以從此信箱中接收消息就很明確了。當一個擁有一個信箱的進程終止時,信箱也要消失。隨後,向這個信箱發送消息的進程都會被告知該信箱已經不存在了。
  另外,操作系統擁有的一個信箱是獨立的且不會依附於任何進程。那麼操作系統必須要提供一種機制以允許一個進程做如下的工作:
  創建一個新信箱;
  通過這個信箱發送和接收消息;
  刪除一個信箱。
  創建了一個新信箱的進程默認爲該信箱的所有者。最初,所有者是唯一能夠從此信箱中接收消息的進程。然而,可以通過系統調用將(信箱的)所有權和接收權交給其他進程。當然,這會造成每個信箱有多個接收者的情況。
  3.管道通信
  所謂管道通信,是指連接兩個進程的一個打開的共享文件。發送進程以字符流的形式將大量的信息寫入管道,接收進程則在需要時從管道中讀出數據。爲了協調雙方的通信,管道通信機制必須對發送進程和接收進程在利用管道進行通信時實施同步和互斥,並且只有在確定雙方存在時才能進行通信。

 

2.1.6 線程概念與多線程模型

  本節將重點介紹線程的概念、作用、實現方式及線程與進程的區別,另外簡單介紹多線程模型。
  1.線程的引入
  在傳統操作系統的單線程進程中,進程和線程概念可以不加區別。圖2-3給出了單線程進程的內存佈局和結構,它由進程控制塊和用戶地址空間,以及管理進程執行的調用/返回行爲的系統堆棧或用戶堆棧構成。一個進程的結構可以劃分爲兩個部分:對資源的管理和實際的指令執行序列。顯然,採用併發多進程程序設計時,併發進程之間的切換和通信均要藉助於操作系統的進程管理和進程通信機制,因而實現代價較大,而較大的進程切換和進程通信代價,又進一步影響了併發的粒度。

  設想是否可以把進程的管理和執行任務相分離,如圖2-4所示,讓進程是操作系統中進行保護和資源分配的單位,允許一個進程中包含多個可併發執行的控制流,這些控制流切換時不必通過進程調度,通信時可以直接藉助於共享內存區,每個控制流稱爲一個線程,這就是併發多線程程序設計。

  多線程進程的內存佈局如圖2-5所示,在多線程環境中,仍然有與進程相關的內容是PCB 和用戶地址空間,而每個線程除了有獨立堆棧,以及包含現場信息和其他狀態信息外,也要設置線程控制塊TCB(Thread Control Block)。線程間的關係較爲密切,一個進程中的所有線程共享其所屬進程擁有的資源,它們駐留在相同的地址空間,可以存取相同的數據。例如,當一個線程改變了主存中的一個數據項時,如果這時其他線程也存取這個數據項的話,它便能看到相同的結果。

  在操作系統中引入進程的目的是爲了使多個程序併發執行,以改善資源利用率及提高系統的吞吐量,那麼,在操作系統中再引入線程,則是爲了減少程序併發執行時所付出的時空開銷,使操作系統具有更好的併發性能。
  線程是進程中的一個實體,是被系統獨立調度和分派的基本單位。線程自己基本上不擁有系統資源,只擁有在運行中必不可少的資源,如線程狀態、寄存器上下文和棧。它同樣有就緒、阻塞和執行三種基本狀態。它可與同屬一個進程的其他線程共享進程所擁有的全部資源。一個線程可以創建和撤銷另一個線程,同一個進程中的多個線程之間可以併發執行。由於線程之間的相互制約,致使線程在運行中也呈現出間斷性。
  2.線程實現方式
  內核線程:它依賴於操作系統內核,由內核的內部需求進行創建和撤銷,用來執行一個指定的函數。一個線程發起系統調用而阻塞,不會影響其他線程。它通過時間片分配給線程,所以,多線程的進程獲得更多CPU時間。
  用戶線程:不依賴於操作系統內核,應用進程利用線程庫提供創建、同步、調度和管理線程的函數來控制用戶線程。調度在應用軟件內部進行,通常採用非搶先式和更簡單的規則,也無須用戶態和核心態切換,所以速度特別快。
  輕權進程:它是操作系統內核支持的用戶線程。一個進程可有一個或多個輕權進程,每個輕權進程由一個單獨的內核線程來支持。
  3.進程機制與線程機制的比較
  在引入線程的操作系統中,通常一個進程有若干個線程,至少也需要有一個線程。下面從5個方面來比較線程和進程。
  調度
  在傳統的操作系統中,進程是擁有資源的基本單位和獨立調度、分派的基本單位。而在引入線程的操作系統中,則把線程作爲調度和分派的基本單位,把進程作爲資源擁有的基本單位。
  併發性
  在引入線程的操作系統中,不僅進程之間可以併發執行,而且在一個進程的多個線程之間,也可併發執行。因而使操作系統具有更好的併發性,從而能夠有效地使用多個資源和提高系統吞吐量。
  擁有資源
  一般來說,線程除了擁有一點必不可少的資源外,它自己不擁有系統資源,但它可以訪問其隸屬進程的資源。也就是說,一個進程所擁有的資源可供它所有的線程共享。
  系統開銷
  在有的系統中,線程的切換、同步和通信都無須操作系統內核的干預。
  通信方面
  進程間通信需要進程同步和互斥手段的輔助,以保證數據一致性,而線程間可以通過直接讀/寫進程數據段(如全局變量)來進行通信。
  4.多線程模型
  線程是操作系統進程中能夠獨立執行的實體(控制流),是處理器調度和分派的基本單位。線程是進程的組成部分,每個進程內允許包含多個併發執行的實體(控制流),這就是多線程。
  許多系統都提供用戶和內核線程支持,從而有不同的多線程模型。下面我們看一下三種常見的線程模型。
  多對一模型
  多對一模型(如圖2-6所示)將多個用戶線程映射到一個內核線程。線程管理是在用戶空間進行的,因而效率比較高;但是,如果一個線程執行了阻塞系統調用,那麼整個進程就會阻塞。而且,因爲任一時刻只有一個線程能訪問內核,所以多個線程不能並行運行在多處理器上。
  一對一模型
  一對一模型(如圖2-7所示)將每個用戶線程映射到一個內核線程。該模型在一個線程執行阻塞系統調用時,能允許另一個線程繼續執行,所以,它提供了比多對一模型更好的併發功能;它也允許多個線程能在多處理系統上並行地運行。這種模型的唯一缺點是,創建一個用戶線程需要一個相應的內核線程。由於創建內核線程的開銷會影響應用程序的性能,所以,這種模型的實現大多數限制了系統所支持的線程數量。
  多對多模型
  多對多模型(如圖2-8所示)是多路複用許多用戶線程到同樣數量或更小數量的內核線程上。內核線程的數量可能與特定應用程序或特定機器有關(位於多處理器上的應用程序可比單處理器上的應用程序分配更多數量的內核線程)。雖然多對一模型允許開發人員隨意創建任意多的用戶線程,但是由於內核只能一次調度一個線程,所以並不能增加併發性。一對一模型提供了更大的併發性,但是開發人員必須小心,不要在應用程序內創建太多的線程。而多對多模型沒有這兩方面的缺點,開發人員可創建任意多的必要用戶線程,並且相應內核線程能在多處理器系統上並行執行。並且,當一個線程執行阻塞系統調用時,內核能調度另一個線程來執行。
  5.併發多線程程序設計的優點
  在一個進程中包含多個並行執行的控制流,而不是把多個可併發執行的控制流一一分散在多個進程中,這是併發多線程程序設計與併發多進程程序設計的不同之處。併發多線程程序設計的主要優點是使系統性能獲得很大提高,具體表現在以下幾個方面。

       

  快速線程切換。進程具有獨立的虛地址空間,以進程爲單位進行任務調度,系統必須交換地址空間,切換時間長,而在同一進程中的多線程共享同一地址空間,因而,能使線程快速切換。
  減少(系統)管理開銷。對多個進程的管理(創建、調度、終止等)系統開銷大,如在響應客戶請求建立一個新的服務進程的服務器應用中,創建的開銷比較顯著。面對創建、終止線程,雖然也有系統開銷,但要比進程小得多。
  (線程)通信易於實現。爲了實現協作,進程或線程間需要交換數據。對於自動共享同一地址空間的各個線程來說,所有全局數據均可自由訪問,不需什麼特殊設施就能實現數據共享。而進程通信則相當複雜,必須藉助諸如通信機制、消息緩衝、管道機制等設施,並且還要調用內核功能才能實現,同時線程通信的效率也很高。
  併發程度提高。許多多任務操作系統限制用戶能擁有的最多進程數目,如早期的UNIX 一般爲50個,這對許多併發應用來說是不夠的。而對多線程技術來說,一般可達幾千個,基本上不存在線程數目的限制。
  節省內存空間。多線程合用進程地址空間,而不同進程獨佔地址空間,使用不經濟。
  由於隊列管理和處理器調度是以線程爲單位的,因此,多數涉及執行的狀態信息被維護在線程數據結構中。然而,有一些影響到一個進程中所有線程的活動,操作系統必須在進程級進行管理。掛起意味着將主存中的地址空間對換到磁盤上,因爲,在一個進程中的所有線程共享同一地址空間,此時,所有線程也必須進入掛起狀態。相似地,終止一個進程時,所有線程應被終止。

2.1.7 線程管理與線程池

  多線程技術是利用線程池來提供一整套有關線程的原語集來支持多線程運行的,有的操作系統直接支持多線程,而有的操作系統不支持多線程。因而,線程池可以分成兩種:用戶空間中運行的線程池和內核中運行的線程池。一般來說,線程池至少應提供以下功能的原語調用:孵化、封鎖、活化、結束、通信、同步、互斥等,以及切換(保護和恢復線程上下文)的代碼,調度(對線程的調度算法及實施處理器調度)的代碼。同時應提供一組與線程有關的應用程序編程接口API,支持應用程序創建、調度、撤銷和管理線程的運行。
  基本的線程控制原語有如下4種。
  孵化(spawn):又稱創建線程。當一個新進程被生成後,該進程的一個線程也就被創建。此後,該進程中的一個線程可以孵化同一進程中的其他線程,併爲新線程提供指令計數器和參數。一個新線程還將被分配寄存器上下文和堆棧空間,並將其加入就緒隊列。
  封鎖(block):又稱線程阻塞或等待。當一個線程等待一個事件時,將變成阻塞態,在保護它的用戶寄存器、程序計數器和堆棧指針等現場後,處理器就可以轉向執行其他就緒線程。
  活化(unblock):又稱恢復線程。當被阻塞線程等待的事件發生時,線程變成就緒態或相應狀態。
  結束(finish):又稱撤銷線程。當一個線程正常完成時,便回收它佔有的寄存器和堆棧等資源,撤銷線程TCB。當一個線程運行出現異常時,允許強行撤銷一個線程。
  對於在用戶空間運行的線程池,由於它完全在用戶空間中運行,操作系統內核對線程池不可見,而僅僅知道管理的是一般的單線程進程。這種情況下,線程池起到一個微內核的作用,實質上是多線程應用程序的開發和運行支撐環境。其優點是:節省了內核的寶貴資源,減少系統態和用戶態之間的切換,因而,線程池的運行開銷小、效率高;容易按特定應用的需要選擇進程調度算法,也就是說,線程池的線程調度算法與操作系統的低級調度算法是無關的;能在任何操作系統上運行。其缺點是:當線程執行一個系統調用時,不僅該線程被阻塞,而且,進程內的所有線程會被阻塞,這種多線程應用就不能充分利用多處理器的優點。
  在內核中運行的線程池,則是通過內核來管理線程池的。內核中不但要保存進程的數據結構,也要建立和維護線程的數據結構及保存每個線程的入口,線程管理的所有工作由操作系統內核來實現。由內核專門提供一組應用程序編程接口(API),供開發者開發多線程應用程序。其優點是:能夠調度同一進程中多個線程同時在處理器上並行執行,充分發揮多處理器的能力,若進程中的一個線程被阻塞了,內核能調度同一進程的其他線程佔有處理器的運行,也可以調度其他進程中的線程運行。其缺點是:在同一進程中,控制權從一個線程傳送到另一個線程時需要用戶態-系統態-用戶態的模式切換,系統開銷較大。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章