1. 程式人生 > >【Linux 執行緒】同一個程序中的執行緒共享哪些資源

【Linux 執行緒】同一個程序中的執行緒共享哪些資源

程序是具有一定獨立功能的程式關於某個資料集合上的一次執行活動,程序是系統進行資源分配和排程的一個獨立單位. 

執行緒是程序的一個實體,是CPU排程和分派的基本單位,它是比程序更小的能獨立執行的基本單位.執行緒自己基本上不擁有系統資源,只擁有一點在執行中必不可少的資源(如程式計數器,一組暫存器和棧),但是它可與同屬一個程序的其他的執行緒共享程序所擁有的全部資源

一個執行緒可以建立和撤銷另一個執行緒;     同一個程序中的多個執行緒之間可以併發執行.

程序在執行過程中擁有獨立的記憶體單元,而該程序的多個執行緒共享記憶體,從而極大地提高了程式的執行效率

。 

每個獨立的執行緒有一個程式執行的入口、順序執行序列和程式的出口。但是執行緒不能夠獨立執行,必須依存在應用程式中,由應用程式提供多個執行緒執行控制。 

從邏輯角度來看,多執行緒的意義在於一個應用程式中,有多個執行部分可以同時執行。但作業系統並沒有將多個執行緒看做多個獨立的應用,來實現程序的排程和管理以及資源分配。這就是程序和執行緒的重要區別。

在很多現代作業系統中,一個程序的(虛)地址空間大小為4G,分為系統(核心?)空間和使用者空間兩部分,系統空間為所有程序共享,而使用者空間是獨立的,一般WINDOWS程序的使用者空間為2G。 


一個程序中的所有執行緒共享該程序的地址空間,但它們有各自獨立的(/私有的)棧(stack)

,Windows執行緒的預設堆疊大小為1M。堆(heap)的分配與棧有所不同,一般是一個程序有一個C執行時堆,這個堆為本程序中所有執行緒共享,windows程序還有所謂程序預設堆,使用者也可以建立自己的堆。 
用作業系統術語,執行緒切換的時候實際上切換的是一個可以稱之為執行緒控制塊的結構(TCB?),裡面儲存所有將來用於恢復執行緒環境必須的資訊,包括所有必須儲存的暫存器集,執行緒的狀態等。

 

堆:是大家共有的空間,分全域性堆和區域性堆。全域性堆就是所有沒有分配的空間,區域性堆就是使用者分配的空間。堆在作業系統對程序初始化的時候分配,執行過程中也可以向系統要額外的堆,但是記得用完了要還給作業系統,要不然就是記憶體洩漏。


棧:是每個執行緒獨有的,儲存其執行狀態和區域性自動變數的。棧線上程開始的時候初始化,每個執行緒的棧互相獨立,因此,棧是 thread safe的。作業系統在切換執行緒的時候會自動的切換棧,就是切換 SS/ESP暫存器。棧空間不需要在高階語言裡面顯式的分配和釋放。

程序簡說:

程序就是程式的一次執行。

程序是為了在CPU上實現多道程式設計而發明的一個概念。

事實上我們說執行緒是程序裡面的一個執行上下文,或者執行序列,顯然一個程序可以同時擁有多個執行序列,更加詳細的描述是,舞臺上有多個演員同時出場,而這些演員和舞臺就構成了一齣戲,類比程序和執行緒,每個演員是一個執行緒,舞臺是地址空間,這個同一個地址空間裡面的所有執行緒就構成了程序。

比如當我們開啟一個word程式,其實已經同時開啟了多個執行緒,這些執行緒一個負責顯示,一個接受輸入,一個定時進行存檔,這些執行緒一起運轉讓我們感到我們的輸入和螢幕顯示同時發生,而不用鍵入一些字元等好長時間才能顯示到螢幕上

執行緒管理:

執行緒共有的資訊存放在程序控制塊中(PCB),將執行緒獨有的資訊存放線上程控制塊中(TCB)

那麼如何區分哪些資訊是共享的?哪些資訊是獨享的呢?

一般的評價標準是:如果某些資源不獨享會導致執行緒執行錯誤,則該資源就由每個執行緒獨享,而其他資源都由程序裡面的所有執行緒共享。

那麼對於程序及執行緒的實現做如何解釋呢?

首先應該明白程序的排程,建立等實質上都是由作業系統實現的,所以說程序的實現只能由作業系統核心來實現,而不存在使用者態實現的情況。但是對於執行緒就不同了,執行緒的管理者可以是使用者也可以是作業系統本身,執行緒是程序內部的東西,當然存在由程序直接管理執行緒的可能性。因此執行緒的實現就應該分為核心態執行緒實現和使用者態執行緒實現。

 

[核心態執行緒實現]:

執行緒是程序的不同執行序列,也就是說執行緒是獨立執行的基本單位,也是CPU排程的基本單位。那麼作業系統是如何實現管理執行緒的呢?

       首先作業系統向管理程序一樣,應該保持維護執行緒的所有資源,將執行緒控制塊存放在作業系統的核心空間中。那麼此時作業系統就同時掌管程序控制塊和執行緒控制塊

作業系統管理執行緒的好處是:

1.使用者程式設計簡單;

2.如果一個執行緒執行阻塞操作,作業系統可以從容的排程另外一個執行緒的執行。


核心執行緒的實現缺點是:

1.效率低,因為執行緒在核心態實現,每次執行緒切換都需要陷入到核心,由作業系統來排程,而有使用者態切換到核心態是要話費很多時間的,另外核心態實現會佔用核心稀有的資源,因為作業系統要維護執行緒列表,作業系統所佔核心空間一旦裝載後就無法動態改變,並且執行緒的數量遠遠大於程序的數量,隨著執行緒數的增加核心將耗盡

2.核心態的實現需要修改作業系統,這個是誰都不想要做的事情;

 

那麼使用者態是如何實現管理執行緒的呢?

使用者態管理執行緒就是使用者自己做執行緒的切換,自己管理執行緒的資訊,作業系統無需知道執行緒的存在

在使用者態下進行執行緒的管理需要使用者建立一個排程執行緒。一個執行緒在執行完一段時間後主動把資源釋放給其他執行緒使用,而在核心態下則無需如此,因為作業系統可通過週期性的時鐘中斷把控制權奪過來,在使用者態實現情況下,執行系統的排程器也是執行緒,沒有能力奪取控制權。


使用者態實現有什麼優點?

 首先是靈活,因為作業系統不用知道執行緒的存在,所以任何作業系統上都能應用;

其次,執行緒切換快,因為切換在使用者態進行,無需陷入帶核心態;

再次,不用修改作業系統實現容易。


使用者態實現的缺點呢?

       首先程式設計起來很詭異,由於在使用者態下各個程序間需要相互合作才能正常運轉。那麼在程式設計時必須考慮什麼情況下讓出CPU,讓其他的執行緒執行,而讓出時機的選擇對執行緒的效率和可靠性有很大影響,這個並不容易做到;

       其次,使用者態執行緒實現無法完全達到執行緒提出所要達到的目的:程序級多道程式設計;,如果在執行過程中一個執行緒受阻,它將無法將控制權交出來,這樣整個程序都無法推進。作業系統隨即把CPU控制權交給另外一個程序。這樣,一個執行緒受阻造成整個程序受阻,我們期望的通過執行緒對程序實施分身的計劃就失敗了。這是使用者態執行緒致命的缺點。

       排程器啟用:執行緒阻塞後,CPU控制權交給了作業系統,要啟用受阻程序的執行緒,唯一的辦法就是讓作業系統在程序切換時先不切換,而是通知受阻的程序執行系統(即呼叫執行系統),並問其是否還有別的執行緒可以執行。如果有,將CPU控制權交給該受阻程序的執行系統執行緒,從而排程另一個可以執行的執行緒到CPU上。一個程序掛起後,作業系統並不立即切換到別的程序上,而是給該程序二次機會,讓其繼續執行。如果該程序只有一個執行緒,或者其所有執行緒都已經阻塞,則控制權將再次返回給作業系統。而現在,作業系統就會切換到其他執行緒了。

現在作業系統的執行緒實現模型:

使用者態的執行負責程序內部執行緒在非阻塞時,即我們同時實現核心態和使用者態執行緒管理。每個核心態執行緒可以服務一個或者更多個使用者態執行緒。

執行緒從使用者態切換到核心態:

什麼情況下會造成執行緒從使用者態到核心態的切換呢?

首先,如果在程式執行過程中發生中斷或者異常,系統將自動切換到核心態來執行中斷或異常處理機制。

此外,程式進行系統呼叫也會從使用者態切換到核心態。

 

轉自:https://www.cnblogs.com/baoendemao/p/3804677.html