關於程式和執行緒 自我的一些總結

GG_Bond發表於2019-05-09

關於程式和執行緒 自我的一些總結

程式

程式是一個具有一定獨立功能的程式在一個資料集上的一次動態執行的過程,是作業系統進行資源分配和排程的一個獨立單位,是應用程式執行的載體。
程式一般由程式,資料集合,程式控制塊三部分組成。
程式用於描述程式要完成的功能,是控制程式執行的指令集;
資料集合是程式在執行時所需要的資料和工作區;
程式控制塊(Program Control Block,簡稱PCB),包含程式的描述資訊和控制資訊,是程式存在的唯一標誌。

程式具有的特徵:

  • 動態性:程式是程式的一次執行過程,是臨時的,有生命期的,是動態產生,動態消亡的;
  • 併發性:任何程式都可以同其他程式一起併發執行;
  • 獨立性:程式是系統進行資源分配和排程的一個獨立單位;
  • 結構性:程式由程式、資料和程式控制塊三部分組成。

執行緒

執行緒(Thread),有時被稱為輕量級程式(LightweightProcess,LWP),是程式執行流的最小單元。一個標準的執行緒由執行緒ID,當前指令指標(PC),暫存器集合和堆疊組成。通常意義上,一個程式由一個到多個執行緒組成,各個執行緒之間共享程式的記憶體空間及一些程式級的資源。

核心執行緒與使用者執行緒

核心執行緒(Kernel Thread, KLT)就是直接由作業系統核心支援的執行緒,這種執行緒由核心來完成執行緒切換,核心通過操作排程器對執行緒進行排程,並負責將執行緒的任務對映到各個處理器上。一般一個處理核心對應一個核心執行緒。
使用者執行緒就是我們通常意義上所講的輕量級程式執行緒。
使用者執行緒與核心執行緒的對應關係有三種模型:

  • 一對一模型
  • 多對一模型
  • 多對多模型

在現在流行的作業系統中,大都採用多對多的模型。

執行緒排程

在單處理器對應多執行緒的情況下,併發是一種模擬出來的狀態。作業系統會讓這些多執行緒程式輪流執行,每次僅執行一小段時間(通常是幾十到幾百個毫秒),這樣每個執行緒就“看起來”在同時執行。這樣的一個不斷在處理器上切換不同的執行緒的行為為執行緒排程。
執行緒排程中,執行緒通常有三個狀態:

  • 執行(Running):此時執行緒正在執行
  • 就緒(Ready):此時執行緒可以立即執行,但CPU已經被佔用。
  • 等待(Watching):此時執行緒正在等待某一事件(通常是I/O)發生,無法執行。

時間片和狀態之間的關係

處於執行中的執行緒擁有一段可以執行的時間,這段時間稱為時間片(Time Slice)。
當時間片用盡時,該執行緒進去就緒狀態。
如果在時間片用盡之前執行緒就開始等待某件事。那麼它會進入等待狀態。
當一個執行緒離開執行狀態時,排程系統就會選擇一個其他的就緒執行緒繼續執行。
在一個處於等待狀態的執行緒所等待的時間發生之後,該執行緒進入就緒狀態。

執行緒優先順序和優先順序排程

優先順序排程決定了執行緒按照什麼順序輪流執行,在具有優先順序排程的系統中,執行緒擁有各自的執行緒優先順序(Thread Priority)。具有高優先順序的執行緒會更早地執行,而低優先順序的執行緒通常要等沒有更高優先順序的可執行執行緒時才會被執行。
執行緒的優先順序可以由使用者手動設定,此外系統也會根據不同情形調整優先順序。
線上程排程機制下存在執行緒餓死現象。一個執行緒餓死是說它的優先順序較低,在它執行之前總是有比它優先順序更高的執行緒等待執行,因此這個低優先順序的執行緒始終得不到執行。為了避免執行緒餓死,排程系統通常會逐步提升那些等待了很久而得不到執行的執行緒的優先順序。這樣,一個執行緒只要等待了足夠長的時間,其優先順序總會被提升到可以讓它執行的程度,也就是說這種情況下執行緒終會得到執行,只是時間的問題。
在優先順序排程環境下,執行緒優先順序的改變有三種方式:

  1. 使用者指定優先順序
  2. 根據進入等待狀態的頻繁程度提升或降低優先順序(由作業系統完成)
  3. 長時間得不到執行而被提升優先順序。

執行緒安全,同步,鎖

多執行緒程式處於一個多變的環境當中,可訪問的全域性變數和堆資料隨時都可以被其他的執行緒改變。因此多執行緒程式在併發時資料的一致性非常重要。
為了避免多個執行緒同時讀寫同一個資料而產生預料不到的後果,我們將各個執行緒堆同一個資料的訪問同步(Synchronization) 。所謂同步(synchronization)就是指一個執行緒訪問資料時,其它執行緒不得對同一個資料進行訪問,即同一時刻只能有一個執行緒訪問該資料,當這一執行緒訪問結束時其它執行緒才能對這它進行訪問。
同步最常見的方式就是使用鎖(Lock) ,也稱為執行緒鎖。鎖是一種非強制機制,每一個執行緒在訪問資料或資源之前,首先試圖獲取(Acquire)鎖,並在訪問結束之後釋放(Release)鎖。在鎖被佔用時試圖獲取鎖,執行緒會進入等待狀態,直到鎖被釋放再次變為可用。

二元訊號量

二元訊號量(Binary Semaphore)是一種最簡單的鎖,它有兩種狀態:佔用和非佔用。它適合只能被唯一一個執行緒獨佔訪問的資源。當二元訊號量處於非佔用狀態時,第一個試圖獲取該二元訊號量鎖的執行緒會獲得該鎖,並將二元訊號量鎖置為佔用狀態,之後其它試圖獲取該二元訊號量的執行緒會進入等待狀態,直到該鎖被釋放。

多元訊號量

多元訊號量允許多個執行緒訪問同一個資源,多元訊號量簡稱訊號量(Semaphore),對於允許多個執行緒併發訪問的資源,這是一個很好的選擇。一個初始值為N的訊號量允許N個執行緒併發訪問。執行緒訪問資源時首先獲取訊號量鎖,進行如下操作:

  1. 將訊號量的值減1;
  2. 如果訊號量的值小於0,則進入等待狀態,否則繼續執行;

訪問資源結束之後,執行緒釋放訊號量鎖,進行如下操作:

  1. 將訊號量的值加1;
  2. 如果訊號量的值小於1(等於0),喚醒一個等待中的執行緒;

互斥量

互斥量(Mutex)和二元訊號量類似,資源僅允許一個執行緒訪問。與二元訊號量不同的是,訊號量在整個系統中可以被任意執行緒獲取和釋放,也就是說,同一個訊號量可以由一個執行緒獲取而由另一執行緒釋放。而互斥量則要求哪個執行緒獲取了該互斥量鎖就由哪個執行緒釋放,其它執行緒無法釋放互斥量。

臨界區

臨界區(Critical Section)是一種比互斥量更加嚴格的同步手段。互斥量和訊號量在系統的任何程式都是可見的,也就是說一個程式建立了一個互斥量或訊號量,另一程式試圖獲取該鎖是合法的。而臨界區的作用範圍僅限於本程式,其它的程式無法獲取該鎖。除此之處,臨界區與互斥量的性質相同。

讀寫鎖

讀寫鎖(Read-Write Lock)允許多個執行緒同時對同一個資料進行讀操作,而只允許一個執行緒進行寫操作。這是因為讀操作不會改變資料的內容,是安全的;而寫操作會改變資料的內容,是不安全的。對同一個讀寫鎖,有兩種獲取方式:共享的(Shared)和獨佔的(Exclusive)。當鎖處於自由狀態時,試圖以任何一種方式獲取鎖都能成功,並將鎖置為對應的狀態;如果鎖處於共享狀態,其它執行緒以共享方式獲取該鎖,仍然能成功,此時該鎖分配給了多個執行緒;如果其它執行緒試圖如獨佔的方式獲取處於共享狀態的鎖,它必須等待所有執行緒釋放該鎖;處於獨佔狀態的鎖阻止任何執行緒獲取該鎖,不論它們以何種方式。獲取讀寫鎖的方式總結如下:

讀寫鎖的狀態 以共享方式獲取 以獨佔方式獲取
自由 成功 成功
共享 成功 等待
獨佔 等待 等待

可重入(Reentrant)

一個函式被重入,表示這個函式沒有執行完成,由於外部因素或內部呼叫,又一次進入該函式執行。一個函式要被重入,只有兩種情況:

  1. 多個執行緒同時執行這個函式
  2. 函式自身(可能是經過多層呼叫之後)呼叫自身。

一個函式被稱為可重入的,表明該函式被重入之後不會產生任何不良後果。舉個例子,如下這個sqr函式是可重入的

int sqr(int x)  
 {  
   return x*x;  
 }  

一個函式要稱為可重入的,必須包含這幾個特點:

  • 不適用任何(區域性)靜態過全域性的飛const變數
  • 不反悔任何(區域性)靜態或全域性的非const變數的指標
  • 僅依賴於呼叫方法的引數。
  • 不依賴任何單個資源的鎖(mutex)等
  • 不呼叫任何不可重入的函式。

可重入是併發安全的強力保障,一個可重入的函式可以在多執行緒環境下放心使用。

使用多執行緒的優點

  1. 多執行緒技術使程式的響應速度更快 ,因為使用者介面可以在進行其它工作的同時一直處於活動狀態;
  2. 當前沒有進行處理的任務時可以將處理器時間讓給其它任務;
  3. 佔用大量處理時間的任務可以定期將處理器時間讓給其它任務;
  4. 可以隨時停止任務;
  5. 可以分別設定各個任務的優先順序以優化效能。

程式與執行緒的區別

  1. 執行緒是程式執行的最小單位,而程式是作業系統分配資源的最小單位;
  2. 一個程式由一個或多個執行緒組成,執行緒是一個程式中程式碼的不同執行路線;
  3. 程式之間相互獨立,但同一程式下的各個執行緒之間共享程式的記憶體空間(包括程式碼段、資料集、堆等)及一些程式級的資源(如開啟檔案和訊號),某程式內的執行緒在其它程式不可見;
  4. 排程和切換:執行緒上下文切換比程式上下文切換要快得多。
  5. 程式在執行過程中擁有獨立的記憶體單元,而多個執行緒共享記憶體,從而極大地提高了程式的執行效率。而執行緒在執行過程中,每個獨立的執行緒有一個程式執行的入口、順序執行序列和程式的出口。但是執行緒不能夠獨立執行,必須依存在應用程式中,由應用程式提供多個執行緒執行控制。

以上總結參考了以下內容:

  1. 《程式設計師的自我修養》
  2. 程式設計思想之多執行緒與多程式(1)
  3. 程式設計思想之多執行緒與多程式(2)
  4. 程式和執行緒關係及區別

相關文章