進程是一個具備必定獨立功能的程序在一個數據集上的一次動態執行的過程,是操做系統進行資源分配和調度的一個獨立單位,是應用程序運行的載體。
進程通常由程序,數據集合,進程控制塊三部分組成。
程序用於描述進程要完成的功能,是控制進程執行的指令集;
數據集合是程序在執行時所須要的數據和工做區;
程序控制塊(Program Control Block,簡稱PCB),包含進程的描述信息和控制信息,是進程存在的惟一標誌。程序員
線程(Thread),有時被稱爲輕量級進程(LightweightProcess,LWP),是程序執行流的最小單元。一個標準的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成。一般意義上,一個進程由一個到多個線程組成,各個線程之間共享程序的內存空間及一些進程級的資源。編程
內核線程(Kernel Thread, KLT)就是直接由操做系統內核支持的線程,這種線程由內核來完成線程切換,內核經過操做調度器對線程進行調度,並負責將線程的任務映射到各個處理器上。通常一個處理核心對應一個內核線程。
用戶線程就是咱們一般意義上所講的輕量級進程線程。
用戶線程與內核線程的對應關係有三種模型:安全
在如今流行的操做系統中,大都採用多對多的模型。多線程
在單處理器對應多線程的狀況下,併發是一種模擬出來的狀態。操做系統會讓這些多線程程序輪流執行,每次僅執行一小段時間(一般是幾十到幾百個毫秒),這樣每一個線程就「看起來」在同時執行。這樣的一個不斷在處理器上切換不一樣的線程的行爲爲線程調度。
線程調度中,線程一般有三個狀態:併發
處於運行中的線程擁有一段能夠執行的時間,這段時間稱爲時間片(Time Slice)。
當時間片用盡時,該線程進去就緒狀態。
若是在時間片用盡以前線程就開始等待某件事。那麼它會進入等待狀態。
當一個線程離開運行狀態時,調度系統就會選擇一個其餘的就緒線程繼續執行。
在一個處於等待狀態的線程所等待的時間發生以後,該線程進入就緒狀態。函數
優先級調度決定了線程按照什麼順序輪流執行,在具備優先級調度的系統中,線程擁有各自的線程優先級(Thread Priority)。具備高優先級的線程會更早地執行,而低優先級的線程一般要等沒有更高優先級的可執行線程時纔會被執行。
線程的優先級能夠由用戶手動設置,此外系統也會根據不一樣情形調整優先級。
在線程調度機制下存在線程餓死現象。一個線程餓死是說它的優先級較低,在它執行以前老是有比它優先級更高的線程等待執行,所以這個低優先級的線程始終得不到執行。爲了不線程餓死,調度系統一般會逐步提高那些等待了好久而得不到執行的線程的優先級。這樣,一個線程只要等待了足夠長的時間,其優先級總會被提高到可讓它執行的程度,也就是說這種狀況下線程終會獲得執行,只是時間的問題。
在優先級調度環境下,線程優先級的改變有三種方式:性能
多線程程序處於一個多變的環境當中,可訪問的全局變量和堆數據隨時均可以被其餘的線程改變。所以多線程程序在併發時數據的一致性很是重要。
爲了不多個線程同時讀寫同一個數據而產生預料不到的後果,咱們將各個線程堆同一個數據的訪問同步(Synchronization) 。所謂同步(synchronization)就是指一個線程訪問數據時,其它線程不得對同一個數據進行訪問,即同一時刻只能有一個線程訪問該數據,當這一線程訪問結束時其它線程才能對這它進行訪問。
同步最多見的方式就是使用鎖(Lock) ,也稱爲線程鎖。鎖是一種非強制機制,每個線程在訪問數據或資源以前,首先試圖獲取(Acquire)鎖,並在訪問結束以後釋放(Release)鎖。在鎖被佔用時試圖獲取鎖,線程會進入等待狀態,直到鎖被釋放再次變爲可用。優化
二元信號量 ui
二元信號量(Binary Semaphore)是一種最簡單的鎖,它有兩種狀態:佔用和非佔用。它適合只能被惟一一個線程獨佔訪問的資源。當二元信號量處於非佔用狀態時,第一個試圖獲取該二元信號量鎖的線程會得到該鎖,並將二元信號量鎖置爲佔用狀態,以後其它試圖獲取該二元信號量的線程會進入等待狀態,直到該鎖被釋放。操作系統
多元信號量
多元信號量容許多個線程訪問同一個資源,多元信號量簡稱信號量(Semaphore),對於容許多個線程併發訪問的資源,這是一個很好的選擇。一個初始值爲N的信號量容許N個線程併發訪問。線程訪問資源時首先獲取信號量鎖,進行以下操做:
訪問資源結束以後,線程釋放信號量鎖,進行以下操做:
互斥量
互斥量(Mutex)和二元信號量相似,資源僅容許一個線程訪問。與二元信號量不一樣的是,信號量在整個系統中能夠被任意線程獲取和釋放,也就是說,同一個信號量能夠由一個線程獲取而由另外一線程釋放。而互斥量則要求哪一個線程獲取了該互斥量鎖就由哪一個線程釋放,其它線程沒法釋放互斥量。
臨界區
臨界區(Critical Section)是一種比互斥量更加嚴格的同步手段。互斥量和信號量在系統的任何進程都是可見的,也就是說一個進程建立了一個互斥量或信號量,另外一進程試圖獲取該鎖是合法的。而臨界區的做用範圍僅限於本進程,其它的進程沒法獲取該鎖。除此之處,臨界區與互斥量的性質相同。
讀寫鎖
讀寫鎖(Read-Write Lock)容許多個線程同時對同一個數據進行讀操做,而只容許一個線程進行寫操做。這是由於讀操做不會改變數據的內容,是安全的;而寫操做會改變數據的內容,是不安全的。對同一個讀寫鎖,有兩種獲取方式:共享的(Shared)和獨佔的(Exclusive)。當鎖處於自由狀態時,試圖以任何一種方式獲取鎖都能成功,並將鎖置爲對應的狀態;若是鎖處於共享狀態,其它線程以共享方式獲取該鎖,仍然能成功,此時該鎖分配給了多個線程;若是其它線程試圖如獨佔的方式獲取處於共享狀態的鎖,它必須等待全部線程釋放該鎖;處於獨佔狀態的鎖阻止任何線程獲取該鎖,不論它們以何種方式。獲取讀寫鎖的方式總結以下:
讀寫鎖的狀態 | 以共享方式獲取 | 以獨佔方式獲取 |
---|---|---|
自由 | 成功 | 成功 |
共享 | 成功 | 等待 |
獨佔 | 等待 | 等待 |
一個函數被重入,表示這個函數沒有執行完成,因爲外部因素或內部調用,又一次進入該函數執行。一個函數要被重入,只有兩種狀況:
一個函數被稱爲可重入的,代表該函數被重入以後不會產生任何不良後果。舉個例子,以下這個sqr函數是可重入的
int sqr(int x) { return x*x; }
一個函數要稱爲可重入的,必須包含這幾個特色:
可重入是併發安全的強力保障,一個可重入的函數能夠在多線程環境下放心使用。
以上總結參考瞭如下內容: