進程與線程

進程(process)和線程(thread)是操做系統的基本概念,可是它們比較抽象,不容易掌握。chrome


最近,我讀到一篇材料,發現有一個很好的類比,能夠把它們解釋地清晰易懂。瀏覽器

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

計算機的核心是CPU,它承擔了全部的計算任務。它就像一座工廠,時刻在運行。多線程

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

假定工廠的電力有限,一次只能供給一個車間使用。也就是說,一個車間開工的時候,其餘車間都必須停工。背後的含義就是,單個CPU一次只能運行一個任務。併發

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

進程就比如工廠的車間,它表明CPU所能處理的單個任務。任一時刻,CPU老是運行一個進程,其餘進程處於非運行狀態。ide

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

一個車間裏,能夠有不少工人。他們協同完成一個任務。工具

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

線程就比如車間裏的工人。一個進程能夠包括多個線程。性能


watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=車間的空間是工人們共享的,好比許多房間是每一個工人均可以進出的。這象徵一個進程的內存空間是共享的,每一個線程均可以使用這些共享內存。spa

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

但是,每間房間的大小不一樣,有些房間最多隻能容納一我的,好比廁所。裏面有人的時候,其餘人就不能進去了。這表明一個線程使用某些共享內存時,其餘線程必須等它結束,才能使用這一塊內存。操作系統

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

一個防止他人進入的簡單方法,就是門口加一把鎖。先到的人鎖上門,後到的人看到上鎖,就在門口排隊,等鎖打開再進去。這就叫"互斥鎖"(Mutual exclusion,縮寫 Mutex),防止多個線程同時讀寫某一塊內存區域。線程

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

還有些房間,能夠同時容納n我的,好比廚房。也就是說,若是人數大於n,多出來的人只能在外面等着。這比如某些內存區域,只能供給固定數目的線程使用。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

這時的解決方法,就是在門口掛n把鑰匙。進去的人就取一把鑰匙,出來時再把鑰匙掛回原處。後到的人發現鑰匙架空了,就知道必須在門口排隊等着了。這種作法叫作"信號量"(Semaphore),用來保證多個線程不會互相沖突。


不難看出,mutex是semaphore的一種特殊狀況(n=1時)。也就是說,徹底能夠用後者替代前者。可是,由於mutex較爲簡單,且效率高,因此在必須保證資源獨佔的狀況下,仍是採用這種設計。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

操做系統的設計,所以能夠歸結爲三點:


(1)以多進程形式,容許多個任務同時運行;

(2)以多線程形式,容許單個任務分紅不一樣的部分運行;

(3)提供協調機制,一方面防止進程之間和線程之間產生衝突,另外一方面容許進程之間和線程之間共享資源。






什麼是線程


什麼是線程?線程與進程與有什麼關係?這是一個很是抽象的問題,也是一個特別廣的話題,涉及到很是多的知識。我不能確保能把它講的話,也不能確保講的內容所有都正確。即便這樣,我也但願儘量地把他講通俗一點,講的明白一點,由於這是個一直困擾我好久的,撲朔迷離的知識領域,但願經過個人理解揭開它一層一層神祕的面紗。

 

任務調度


線程是什麼?要理解這個概念,需要先了解一下操做系統的一些相關概念。大部分操做系統(如Windows、Linux)的任務調度是採用時間片輪轉的搶佔式調度方式,也就是說一個任務執行一小段時間後強制暫停去執行下一個任務,每一個任務輪流執行。任務執行的一小段時間叫作時間片,任務正在執行時的狀態叫運行狀態,任務執行一段時間後強制暫停去執行下一個任務,被暫停的任務就處於就緒狀態等待下一個屬於它的時間片的到來。這樣每一個任務都能獲得執行,因爲CPU的執行效率很是高,時間片很是短,在各個任務之間快速地切換,給人的感受就是多個任務在「同時進行」,這也就是咱們所說的併發(別以爲併發有多高深,它的實現很複雜,但它的概念很簡單,就是一句話:多個任務同時執行)。多任務運行過程的示意圖以下:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

圖 1:操做系統中的任務調度

 

 

進程


咱們都知道計算機的核心是CPU,它承擔了全部的計算任務;而操做系統是計算機的管理者,它負責任務的調度、資源的分配和管理,統領整個計算機硬件;應用程序側是具備某種功能的程序,程序是運行於操做系統之上的。

進程是一個具備必定獨立功能的程序在一個數據集上的一次動態執行的過程,是操做系統進行資源分配和調度的一個獨立單位,是應用程序運行的載體。進程是一種抽象的概念,歷來沒有統一的標準定義。進程通常由程序、數據集合和進程控制塊三部分組成。程序用於描述進程要完成的功能,是控制進程執行的指令集;數據集合是程序在執行時所須要的數據和工做區;程序控制塊(Program Control Block,簡稱PCB),包含進程的描述信息和控制信息,是進程存在的惟一標誌。

進程具備的特徵:

動態性:進程是程序的一次執行過程,是臨時的,有生命期的,是動態產生,動態消亡的;

併發性:任何進程均可以同其餘進程一塊兒併發執行;

獨立性:進程是系統進行資源分配和調度的一個獨立單位;

結構性:進程由程序、數據和進程控制塊三部分組成。

 

線程


在早期的操做系統中並無線程的概念,進程是能擁有資源和獨立運行的最小單位,也是程序執行的最小單位。任務調度採用的是時間片輪轉的搶佔式調度方式,而進程是任務調度的最小單位,每一個進程有各自獨立的一塊內存,使得各個進程之間內存地址相互隔離。

後來,隨着計算機的發展,對CPU的要求愈來愈高,進程之間的切換開銷較大,已經沒法知足愈來愈複雜的程序的要求了。因而就發明了線程,線程是程序執行中一個單一的順序控制流程,是程序執行流的最小單元,是處理器調度和分派的基本單位。一個進程能夠有一個或多個線程,各個線程之間共享程序的內存空間(也就是所在進程的內存空間)。一個標準的線程由線程ID、當前指令指針(PC)、寄存器和堆棧組成。而進程由內存空間(代碼、數據、進程空間、打開的文件)和一個或多個線程組成。

 

進程與線程的區別


前面講了進程與線程,但可能你還以爲迷糊,感受他們很相似。的確,進程與線程有着千絲萬縷的關係,下面就讓咱們一塊兒來理一理:

1.線程是程序執行的最小單位,而進程是操做系統分配資源的最小單位;

2.一個進程由一個或多個線程組成,線程是一個進程中代碼的不一樣執行路線;

3.進程之間相互獨立,但同一進程下的各個線程之間共享程序的內存空間(包括代碼段、數據集、堆等)及一些進程級的資源(如打開文件和信號),某進程內的線程在其它進程不可見;

4.調度和切換:線程上下文切換比進程上下文切換要快得多。

 

線程與進程關係的示意圖:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

圖 2:進程與線程的資源共享關係

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

圖 3:單線程與多線程的關係

 

總之,線程和進程都是一種抽象的概念,線程是一種比進程更小的抽象,線程和進程均可用於實現併發。

 

在早期的操做系統中並無線程的概念,進程是能擁有資源和獨立運行的最小單位,也是程序執行的最小單位。它至關於一個進程裏只有一個線程,進程自己就是線程。因此線程有時被稱爲輕量級進程(Lightweight Process,LWP)。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

圖 4:早期的操做系統只有進程,沒有線程

後來,隨着計算機的發展,對多個任務之間上下文切換的效率要求愈來愈高,就抽象出一個更小的概念——線程,通常一個進程會有多個(也但是一個)線程。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

圖 5:線程的出現,使得一個進程能夠有多個線程

 

多線程與多核


上面提到的時間片輪轉的調度方式說一個任務執行一小段時間後強制暫停去執行下一個任務,每一個任務輪流執行。不少操做系統的書都說「同一時間點只有一個任務在執行」。那有人可能就要問雙核處理器呢?難道兩個核不是同時運行嗎?

其實「同一時間點只有一個任務在執行」這句話是不許確的,至少它是不全面的。那多核處理器的狀況下,線程是怎樣執行呢?這就須要瞭解內核線程。

多核(心)處理器是指在一個處理器上集成多個運算核心從而提升計算能力,也就是有多個真正並行計算的處理核心,每個處理核心對應一個內核線程。內核線程(Kernel Thread, KLT)就是直接由操做系統內核支持的線程,這種線程由內核來完成線程切換,內核經過操做調度器對線程進行調度,並負責將線程的任務映射到各個處理器上。通常一個處理核心對應一個內核線程,好比單核處理器對應一個內核線程,雙核處理器對應兩個內核線程,四核處理器對應四個內核線程。

如今的電腦通常是雙核四線程、四核八線程,是採用超線程技術將一個物理處理核心模擬成兩個邏輯處理核心,對應兩個內核線程,因此在操做系統中看到的CPU數量是實際物理CPU數量的兩倍,如你的電腦是雙核四線程,打開「任務管理器\性能」能夠看到4個CPU的監視器,四核八線程能夠看到8個CPU的監視器。

 watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

圖 6:雙核四線程在Windows8下查看的結果

超線程技術就是利用特殊的硬件指令,把一個物理芯片模擬成兩個邏輯處理核心,讓單個處理器都能使用線程級並行計算,進而兼容多線程操做系統和軟件,減小了CPU的閒置時間,提升的CPU的運行效率。這種超線程技術(如雙核四線程)由處理器硬件的決定,同時也須要操做系統的支持才能在計算機中表現出來。

 

程序通常不會直接去使用內核線程,而是去使用內核線程的一種高級接口——輕量級進程(Light Weight Process,LWP),輕量級進程就是咱們一般意義上所講的線程(咱們在這稱它爲用戶線程),因爲每一個輕量級進程都由一個內核線程支持,所以只有先支持內核線程,纔能有輕量級進程。用戶線程與內核線程的對應關係有三種模型:一對一模型、多對一模型、多對多模型,在這以4個內核線程、3個用戶線程爲例對三種模型進行說明。

一對一模型

對於一對一模型來講,一個用戶線程就惟一地對應一個內核線程(反過來不必定成立,一個內核線程不必定有對應的用戶線程)。這樣,若是CPU沒有采用超線程技術(如四核四線程的計算機),一個用戶線程就惟一地映射到一個物理CPU的線程,線程之間的併發是真正的併發。一對一模型使用戶線程具備與內核線程同樣的優勢,一個線程因某種緣由阻塞時其餘線程的執行不受影響;此處,一對一模型也可讓多線程程序在多處理器的系統上有更好的表現。

但一對一模型也有兩個缺點:1.許多操做系統限制了內核線程的數量,所以一對一模型會使用戶線程的數量受到限制;2.許多操做系統內核線程調度時,上下文切換的開銷較大,致使用戶線程的執行效率降低。

 

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk= 

圖 7:一對一模型

 

 

多對一模型

多對一模型將多個用戶線程映射到一個內核線程上,線程之間的切換由用戶態的代碼來進行,所以相對一對一模型,多對一模型的線程切換速度要快許多;此外,多對一模型對用戶線程的數量幾乎無限制。但多對一模型也有兩個缺點:1.若是其中一個用戶線程阻塞,那麼其它全部線程都將沒法執行,由於此時內核線程也隨之阻塞了;2.在多處理器系統上,處理器數量的增長對多對一模型的線程性能不會有明顯的增長,由於全部的用戶線程都映射到一個處理器上了。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk= 

圖 8:多對一模型

 

多對多模型

多對多模型結合了一對一模型和多對一模型的優勢,將多個用戶線程映射到多個內核線程上。多對多模型的優勢有:1.一個用戶線程的阻塞不會致使全部線程的阻塞,由於此時還有別的內核線程被調度來執行;2.多對多模型對用戶線程的數量沒有限制;3.在多處理器的操做系統中,多對多模型的線程也能獲得必定的性能提高,但提高的幅度不如一對一模型的高。

在如今流行的操做系統中,大都採用多對多的模型。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk= 

圖 9:多對多模型

 

 

查看進程與線程


一個應用程序多是多線程的,也多是多進程的,如何查看呢?在Windows下咱們只須打開任務管理器就能查看一個應用程序的進程和線程數。按「Ctrl+Alt+Del」或右鍵快捷工具欄打開任務管理器。

查看進程數和線程數:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk= 

圖 10:查看線程數和進程數

在「進程」選項卡下,咱們能夠看到一個應用程序包含的線程數。若是一個應用程序有多個進程,咱們能看到每個進程,如在上圖中,Google的chrome瀏覽器就有多個進程。同時,若是打開了一個應用程序的多個實例也會有多個進程,如上圖中我打開了兩個cmd窗口,就有兩個cmd進程。若是看不到線程數這一列,能夠在點擊「查看\選擇列」菜單,增長監聽的列。

 

查看CPU和內存的使用率:

在性能選項卡中,咱們能夠查看CPU和內存的使用率,根據CPU使用記錄的監視器的個數還能看出邏輯處理核心的個數,如個人雙核四線程的計算機就有四個監視器。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk= 

圖 11:查看CPU和內存的使用率

 

 

線程的生命週期


當線程的數量小於處理器的數量時,線程的併發是真正的併發,不一樣的線程運行在不一樣的處理器上。但當線程的數量大於處理器的數量時,線程的併發會受到一些阻礙,此時並非真正的併發,由於此時至少有一個處理器會運行多個線程。

在單個處理器運行多個線程時,併發是一種模擬出來的狀態。操做系統採用時間片輪轉的方式輪流執行每個線程。如今,幾乎全部的現代操做系統採用的都是時間片輪轉的搶佔式調度方式,如咱們熟悉的Unix、Linux、Windows及Mac OS X等流行的操做系統。

咱們知道線程是程序執行的最小單位,也是任務執行的最小單位。在早期只有進程的操做系統中,進程有五種狀態,建立、就緒、運行、阻塞(等待)、退出。早期的進程至關於如今的只有單個線程的進程,那麼如今的多線程也有五種狀態,如今的多線程的生命週期與早期進程的生命週期相似。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk= 

圖 12:早期進程的生命週期


進程在運行過程有三種狀態:就緒、運行、阻塞,建立和退出狀態描述的是進程的建立過程和退出過程。

建立:進程正在建立,還不能運行。操做系統在建立進程時要進行的工做包括分配和創建進程控制塊表項、創建資源表格並分配資源、加載程序並創建地址空間;

就緒:時間片已用完,此線程被強制暫停,等待下一個屬於他的時間片到來;

運行:此線程正在執行,正在佔用時間片;

阻塞:也叫等待狀態,等待某一事件(如IO或另外一個線程)執行完;

退出:進程已結束,因此也稱結束狀態,釋放操做系統分配的資源。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk= 

圖 13:線程的生命週期

 

建立:一個新的線程被建立,等待該線程被調用執行;

就緒:時間片已用完,此線程被強制暫停,等待下一個屬於他的時間片到來;

運行:此線程正在執行,正在佔用時間片;

阻塞:也叫等待狀態,等待某一事件(如IO或另外一個線程)執行完;

退出:一個線程完成任務或者其餘終止條件發生,該線程終止進入退出狀態,退出狀態釋放該線程所分配的資源。


watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息