42、並發編程之多執行緒理論篇

一 什麼是執行緒

在傳統作業系統中,每個進程有一個地址空間,而且默認就有一個控制執行緒

執行緒顧名思義,就是一條流水線工作的過程,一條流水線必須屬於一個車間,一個車間的工作過程是一個進程

車間負責把資源整合到一起,是一個資源單位,而一個車間內至少有一個流水線

流水線的工作需要電源,電源就相當於cpu

所以,進程只是用來把資源集中到一起(進程只是一個資源單位,或者說資源集合),而執行緒才是cpu上的執行單位。

多執行緒(即多個控制執行緒)的概念是,在一個進程中存在多個控制執行緒,多個控制執行緒共享該進程的地址空間,相當於一個車間內有多條流水線,都共用一個車間的資源。

例如,北京地鐵與上海地鐵是不同的進程,而北京地鐵里的13號線是一個執行緒,北京地鐵所有的線路共享北京地鐵所有的資源,比如所有的乘客可以被所有線路拉。

二 執行緒的創建開銷小

1.創建進程的開銷要遠大於執行緒?

如果我們的軟體是一個工廠,該工廠有多條流水線,流水線工作需要電源,電源只有一個即cpu(單核cpu)

一個車間就是一個進程,一個車間至少一條流水線(一個進程至少一個執行緒)

創建一個進程,就是創建一個車間(申請空間,在該空間內建至少一條流水線)

而建執行緒,就只是在一個車間內造一條流水線,無需申請空間,所以創建開銷小

2.進程之間是競爭關係,執行緒之間是協作關係?

車間直接是競爭/搶電源的關係,競爭(不同的進程直接是競爭關係,是不同的程式設計師寫的程式運行的,迅雷搶佔其他進程的網速,360把其他進程當做病毒乾死)
一個車間的不同流水線式協同工作的關係(同一個進程的執行緒之間是合作關係,是同一個程式寫的程式內開啟動,迅雷內的執行緒是合作關係,不會自己干自己)

三 執行緒與進程的區別

  1. Threads share the address space of the process that created it; processes have their own address space.
  2. Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.
  3. Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.
  4. New threads are easily created; new processes require duplication of the parent process.
  5. Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.
  6. Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.

四 為何要用多執行緒

多執行緒指的是,在一個進程中開啟多個執行緒,簡單的講:如果多個任務共用一塊地址空間,那麼必須在一個進程內開啟多個執行緒。詳細的講分為4點:

  1. 多執行緒共享一個進程的地址空間

  2. 執行緒比進程更輕量級,執行緒比進程更容易創建可撤銷,在許多作業系統中,創建一個執行緒比創建一個進程要快10-100倍,在有大量執行緒需要動態和快速修改時,這一特性很有用

  3. 若多個執行緒都是cpu密集型的,那麼並不能獲得性能上的增強,但是如果存在大量的計算和大量的I/O處理,擁有多個執行緒允許這些活動彼此重疊運行,從而會加快程式執行的速度。

  4. 在多cpu系統中,為了最大限度的利用多核,可以開啟多個執行緒,比開進程開銷要小的多。(這一條並不適用於python)

五 多執行緒的應用舉例

img

開啟一個字處理軟體進程,該進程肯定需要辦不止一件事情,比如監聽鍵盤輸入,處理文字,定時自動將文字保存到硬碟,這三個任務操作的都是同一塊數據,因而不能用多進程。只能在一個進程里並發地開啟三個執行緒,如果是單執行緒,那就只能是,鍵盤輸入時,不能處理文字和自動保存,自動保存時又不能輸入和處理文字。

六 經典的執行緒模型

多個執行緒共享同一個進程的地址空間中的資源,是對一台電腦上多個進程的模擬,有時也稱執行緒為輕量級的進程

而對一台電腦上多個進程,則共享物理記憶體、磁碟、印表機等其他物理資源。

多執行緒的運行也多進程的運行類似,是cpu在多個執行緒之間的快速切換。

img

不同的進程之間是充滿敵意的,彼此是搶佔、競爭cpu的關係,如果迅雷會和QQ搶資源。而同一個進程是由一個程式設計師的程式創建,所以同一進程內的執行緒是合作關係,一個執行緒可以訪問另外一個執行緒的記憶體地址,大家都是共享的,一個執行緒乾死了另外一個執行緒的記憶體,那純屬程式設計師腦子有問題。

類似於進程,每個執行緒也有自己的堆棧

img

不同於進程,執行緒庫無法利用時鐘中斷強制執行緒讓出CPU,可以調用thread_yield運行執行緒自動放棄cpu,讓另外一個執行緒運行。

執行緒通常是有益的,但是帶來了不小程式設計難度,執行緒的問題是:

1.父進程有多個執行緒,那麼開啟的子執行緒是否需要同樣多的執行緒?

如果是,那麼附近某個執行緒被阻塞,那麼copy到子進程後,copy版的執行緒也要被阻塞嗎,想一想nginx的多執行緒模式接收用戶連接。

2.在同一個進程中,如果一個執行緒關閉了問題,而另外一個執行緒正準備往該文件內寫內容呢?

如果一個執行緒注意到沒有記憶體了,並開始分配更多的記憶體,在工作一半時,發生執行緒切換,新的執行緒也發現記憶體不夠用了,又開始分配更多的記憶體,這樣記憶體就被分配了多次,這些問題都是多執行緒編程的典型問題,需要仔細思考和設計。

七 POSIX執行緒

為了實現可移植的執行緒程式,IEEE在IEEE標準1003.1c中定義了執行緒標準,它定義的執行緒包叫Pthread。大部分UNIX系統都支援該標準,簡單介紹如下

img

八 在用戶空間實現的執行緒

執行緒的實現可以分為兩類:用戶級執行緒(User-Level Thread)和內核線執行緒(Kernel-Level Thread),後者又稱為內核支援的執行緒或輕量級進程。在多執行緒作業系統中,各個系統的實現方式並不相同,在有的系統中實現了用戶級執行緒,有的系統中實現了內核級執行緒。

用戶級執行緒內核的切換由用戶態程式自己控制內核切換,不需要內核干涉,少了進出內核態的消耗,但不能很好的利用多核Cpu,目前Linux pthread大體是這麼做的。

img

在用戶空間模擬作業系統對進程的調度,來調用一個進程中的執行緒,每個進程中都會有一個運行時系統,用來調度執行緒。此時當該進程獲取cpu時,進程內再調度出一個執行緒去執行,同一時刻只有一個執行緒執行。

九 在內核空間實現的執行緒

內核級執行緒:切換由內核控制,當執行緒進行切換的時候,由用戶態轉化為內核態。切換完畢要從內核態返回用戶態;可以很好的利用smp,即利用多核cpu。windows執行緒就是這樣的。

img

十 用戶級與內核級執行緒的對比

一: 以下是用戶級執行緒和內核級執行緒的區別:

  1. 內核支援執行緒是OS內核可感知的,而用戶級執行緒是OS內核不可感知的。
  2. 用戶級執行緒的創建、撤消和調度不需要OS內核的支援,是在語言(如Java)這一級處理的;而內核支援執行緒的創建、撤消和調度都需OS內核提供支援,而且與進程的創建、撤消和調度大體是相同的。
  3. 用戶級執行緒執行系統調用指令時將導致其所屬進程被中斷,而內核支援執行緒執行系統調用指令時,只導致該執行緒被中斷。
  4. 在只有用戶級執行緒的系統內,CPU調度還是以進程為單位,處於運行狀態的進程中的多個執行緒,由用戶程式控制執行緒的輪換運行;在有內核支援執行緒的系統內,CPU調度則以執行緒為單位,由OS的執行緒調度程式負責執行緒的調度。
  5. 用戶級執行緒的程式實體是運行在用戶態下的程式,而內核支援執行緒的程式實體則是可以運行在任何狀態下的程式。

二: 內核執行緒的優缺點

優點:

  1. 當有多個處理機時,一個進程的多個執行緒可以同時執行。

缺點:

  1. 由內核進行調度。

三: 用戶進程的優缺點

優點:

  1. 執行緒的調度不需要內核直接參与,控制簡單。
  2. 可以在不支援執行緒的作業系統中實現。
  3. 創建和銷毀執行緒、執行緒切換代價等執行緒管理的代價比內核執行緒少得多。
  4. 允許每個進程訂製自己的調度演算法,執行緒管理比較靈活。
  5. 執行緒能夠利用的表空間和堆棧空間比內核級執行緒多。
  6. 同一進程中只能同時有一個執行緒在運行,如果有一個執行緒使用了系統調用而阻塞,那麼整個進程都會被掛起。另外,頁面失效也會產生同樣的問題。

缺點:

  1. 資源調度按照進程進行,多個處理機下,同一個進程中的執行緒只能在同一個處理機下分時復用

十一 混合實現

用戶級與內核級的多路復用,內核同一調度內核執行緒,每個內核執行緒對應n個用戶執行緒

img