多線程開發之-01-線程與進程

進程

1:進程是指在系統中正在運行的一個應用程序,進程是程序在計算機上的一次執行活動。

2:每個進程之間是相互獨立的, 每個進程均運行在其專用且受保護的內存空間內

(可以在 Mac 的活動指示器查看當前系統內運行的進程)

線程

1:一個進程要想執行任務,必須要有線程,至少有一條線程

2:一個線程的所有任務都是在線程中執行

線程的串行:一個線程中任務的執行是串行的, 也就是說同一時間內一個線程只能執行一個任務

進程和線程的比較

1:線程是 CPU 調用的最小單位

2:進程是 CPU 分配資源和調度的單位

3:iOS中的app都是單進程的,一個進程中可有多個線程,但至少要有一條線程

4:同一個進程內的線程共享進程資源

但是進程有前臺進程和后臺進程之分,用戶看到的進程就是前臺進程,當前臺進程切換到后臺時,會調用appdelegate的代理方法,但是進程本身還在,沒有被kill掉

線程安全:要確保函數線程安全,主要需要考慮的是線程之間的共享變量。屬于同一進程的不同線程會共享進程內存空間中的全局區和堆,而私有的線程空間則主要包括棧和寄存器。因此,對于同一進程的不同線程來說,每個線程的局部變量都是私有的,而全局變量、局部靜態變量、分配于堆的變量都是共享的。在對這些共享變量進行訪問時,如果要保證線程安全,則必須通過加鎖的方式。一個函數被稱為線程安全的,當且僅當被多個并發線程反復調用時,它會一直產生正確的結果。

要確保函數可重入,需滿足一下幾個條件:

1、不在函數內部使用靜態或全局數據

2、不返回靜態或全局數據,所有數據都由函數的調用者提供。

3、使用本地數據,或者通過制作全局數據的本地拷貝來保護全局數據。

4、不調用不可重入函數。

可重入與線程安全并不等同,一般說來,可重入的函數一定是線程安全的,但反過來不一定成立。

如果我們的線程函數不是線程安全的,那在多線程調用的情況下,可能導致的后果是顯而易見的——共享變量的值由于不同線程的訪問,可能發生不可預料的變化,進而導致程序的錯誤,甚至崩潰。

關于線程的堆棧

說一下線程自己的堆棧問題。

是的,生成子線程后,它會獲取一部分該進程的堆棧空間,作為其名義上的獨立的私有空間。(為何是名義上的呢?)由于,這些線程屬于同一個進程,其他線程只要獲取了你私有堆棧上某些數據的指針,其他線程便可以自由訪問你的名義上的私有空間上的數據變量。(注:而多進程是不可以的,因為不同的進程,相同的虛擬地址,基本不可能映射到相同的物理地址)

多線程

一個進程可以開啟多條線程,每條線程可以并行執行不同的任務. 這個技術可以提高程序的執行效率

多線程原理

同一時間,CPU 只能處理一條線程, 只有一條線程在工作

多線程并發執行,其實是 CPU 快速的在多條線程之間調度(切換)

如果 CPU 調度線程的時間足夠快, 就造成了多線程并發執行的假象

說到并行計算,尤其是單臺計算機的并行計算,一定要先建立時間片的概念。

我們現在所用的,不管是Windows還是Linux,一般都稱為多任務操作系統,即,系統允許并行運行多個應用程序。

操作系統一般是按照一定策略,定期給每個活動的進程執行其內部程序的機會,并且每次只執行一小段時間,然后操作系統利用中斷強行退出執行,將當前程序信息壓棧,然后開始執行下一個進程的一小段程序。

通過這樣不斷快速的循環切換,每個程序都獲得執行,在用戶看來,感覺到很多程序都在平行的執行,這就模擬了并行計算。

當然,新的多核CPU以及超線程CPU,內部就有超過1個的CPU執行體,運行時就不是模擬了,而是真的有兩個以上的程序在被執行。

當然在我們程序員看來,只需要理解程序是被操作系統片段執行的,每個片段就是一個時間片,就足夠了。

既然是片段執行,程序員就必須理解,在自己的程序運行時不是獨一無二的,我們看似很順暢的工作,其實是由一個個的執行片段構成的,我們眼中相鄰的兩條語句甚至同一個語句中兩個不同的運算符之間,都有可能插入其他線程或進程的動作。

由于只有一個CPU,一次只能處理程序要求的一部分,如何處理公平,一種方法就是引入時間片,每個程序輪流執行。

時間片輪轉調度

多線程的優點和缺點

優點

1:能適當的提高程序的執行效率

2:能適當提高資源利用率(CPU 內存利用率)

缺點

創建多線程是有開銷的,iOS 下主要成本包括: 內核數據結構,(大約1KB), 棧空間(子線程512KB, 主線程1MB, 也可以使用 -setStackSize: 設置, 但必須是4K 的倍數, 而且最小是16K), 創建線程大約需要90毫秒的創建時間

如果開啟大量線程, 會降低程序的性能

線程越多,CPU 在調度線程上的開銷就越大

程序設計更加復雜: 比如線程之間的通信, 多線程的數據共享

多線程在 iOS 開發中的應用

主線程

一個 iOS 程序運行后, 默認會開啟一條線程, 成為"主線程"或者"UI 線程"

主線程的主要作用

1:顯示/刷新 UI 界面

2:處理 UI 事件(比如點擊事件, 滾動事件, 拖拽事件)

主線程的注意點

1:不要將比較耗時的操作放到主線程

2:耗時操作會卡住主線程, 嚴重影響 UI 的流暢度, 給用戶一種 "卡"的壞體檢

iOS 中多線程的實現方案

技術方案 簡介 語言 線程生命周期 使用頻率

NSThread 使用更加面向對象

簡單易用, 可直接操作線程對象 OC 程序員管理 偶爾使用

GCD 旨在替代 NSThread 的線程技術

充分利用設備的多核 C 自動管理 ? 經常使用

NSOperation 基于 GCD(底層是GCD)

比GCD 多了一些更簡單實用的功能

使用更加面向對象? OC? 自動管理? ? 經常使用

線程是指進程內的一個執行單元,也是進程內的可調度實體

與進程的區別:

(1)地址空間:進程內的一個可執行單元,進程至少有一個線程;他們共享進程的地址空間(也有少量自己的地址空間);而進程有自己獨立的地址空間(多個進程之間一般不會共享地址空間)

(2)資源擁有:進程是資源擁有的單位,同一個進程內的線程共享進程的資源

(3)線程是處理器調度和分派的基本單位

(4)二者均可并發執行,多線程程序的并發性高

(5)進程的切換代價高于線程,多線程的并發性高

進程有獨立的地址空間,一個進程崩潰后,在保護模式下不會對其他進程產生影響,而線程只是第一個進程中的不同執行路徑,線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間,一個線程死掉就等于整個進程死掉,所以多進程的程序要比多線程的程序健壯,但在進程切換時,耗費資源較大,效率要差一些.但對于一些要求同時進行并且又要共享某些變量的并發操作,需要用多線程

2.Unix和windows進程間通信的主要方式

linux系統IPC:

管道(?pipe?):管道是一種半雙工的通信方式,數據只能單向流動,而且只能在具有親緣關系的進程間使用。進程的親緣關系通常是指父子進程關系。

命名管道(named?pipe):?命名管道也是半雙工的通信方式,但是它允許無親緣關系進程間的通信。

信號量(?semophore?):?信號量是一個計數器,可以用來控制多個進程對共享資源的訪問。它常作為一種鎖機制,防止某進程正在訪問共享資源時,其他進程也訪問該資源。因此,主要作為進程間以及同一進程內不同線程之間的同步手段。

消息隊列( message queue ): 消息隊列是由消息的鏈表,存放在內核中并由消息隊列標識符標識。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩沖區大小受限等缺點。

信號(?sinal?):信號是一種比較復雜的通信方式,用于通知接收進程某個事件已經發生。

共享內存(?shared?memory?):共享內存就是映射一段能被其他進程所訪問的內存,這段共享內存由一個進程創建,但多個進程都可以訪問。共享內存是最快的IPC方式,它是針對其他進程間通信方式運行效率低而專門設計的。它往往與其他通信機制,如信號量,配合使用,來實現進程間的同步和通信。

套接字(?socket?):?套解口也是一種進程間通信機制,與其他通信機制不同的是,它可用于不同及其間的進程通信。

windows系統IPC:

剪貼板(Clipboard):當用戶在應用程序中執行剪切或復制操作時,應用程序將選定的數據以一個或多個標準或應用程序定義的格式放在剪貼板中。

WM_COPYDATA消息:當一個應用向另一個應用傳送數據時,發送方只需使用調用SendMessage函數,接收方只需像處理其它消息那樣處理WM_COPYDATA消息,這樣收發雙方就實現了數據共享,它在底層實際上是通過文件映射來實現的。

文件映射(File?Mapping?):使進程把文件內容當作進程地址區間一塊內存那樣來對待。只需簡單的指針操作就可讀取和修改文件的內容。允許多個進程訪問同一文件映射對象,各個進程在它自己的地址空間里接收內存的指針,通過使用這些指針,不同進程就可以讀寫文件的內容,實現了對文件中數據的共享。

共享內存(Shared?Memory)是文件映射的一種特殊情況進程在創建文件映射對象時用0xFFFFFFFF來代替文件句柄(HANDLE),就表示了對應的文件映射對象是從操作系統頁面文件訪問內存,其它進程打開該文件映射對象就可以訪問該內存塊。由于共享內存是用文件映射實現的,所以它也有較好的安全性,也只能運行于同一計算機上的進程之間。

動態數據交換(DDE):是使用共享內存在應用程序之間進行數據交換的一種進程間通信形式。應用程序可以使用DDE進行一次性數據傳輸,也可以當出現新數據時,通過發送更新值在應用程序間動態交換數據。DDE和剪貼板一樣既支持標準數據格式(如文本、位圖等),又可以支持自己定義的數據格式。但它們的數據傳輸機制卻不同,一個明顯區別是剪貼板操作幾乎總是用作對用戶指定操作的一次性應答,如從菜單中選擇Paste命令。盡管DDE也可以由用戶啟動,但它繼續發揮作用一般不必用戶進一步干預。可以發生在單機或網絡中不同計算機的應用程序之間。

郵件槽(Mailslot):提供進程間單向通信能力,任何進程都能建立郵件槽成為郵件槽服務器。其它進程稱為郵件槽客戶,可以通過郵件槽的名字給郵件槽服務器進程發送消息。進來的消息一直放在郵件槽中,直到服務器進程讀取它為止。一個進程既可以是郵件槽服務器也可以是郵件槽客戶,因此可建立多個郵件槽實現進程間的雙向通信。

管道(?pipe?):同上linux系統&命名管道

套接字(Sockets):同上linux系統

3.死鎖

死鎖是指兩個或兩個以上的進程在執行過程中,因爭奪資源而造成的一種互相等待的僵局,若無外力作用,它們都將無法推進下去。

產生死鎖的四個必要條件:

1.互斥條件:一段時間內某資源只由一個進程占有。

2.請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。

3.不剝奪條件:進程已獲得資源,在末使用完之前,不能強行剝奪。

4.循環等待條件:若干進程之間形成一種頭尾相接的循環等待資源關系。

預防死鎖:需要打破必要條件的2,3,4中之一,由于施加的限制條件較嚴格,可能導致系統資源利用率和系統吞吐量降低。

避免死鎖:施加的限制條件較弱,使系統一直處于安全狀態。比如銀行家算法。

檢測死鎖:資源分配圖、死鎖定理。

解除死鎖:剝奪起源、撤銷進程。

4.linux下fork函數

在fork()的調用處,創建一個子進程,并將整個父進程空間會原模原樣地復制到子進程中,包括指令,變量值,程序調用棧,環境變量,緩沖區等。fork調用僅僅被調用一次,卻能夠返回兩次,它可能有三種不同的返回值:

(1)在父進程中,fork返回新創建子進程的進程ID;

(2)在子進程中,fork返回0;

(3)如果出現錯誤,fork返回一個負值;

在fork函數執行完畢后,如果創建新進程成功,則出現兩個進程,一個是子進程,一個是父進程。在子進程中,fork函數返回0,在父進程中,fork返回新創建子進程的進程ID。我們可以通過fork返回的值來判斷當前進程是子進程還是父進程。

fork出錯可能有兩種原因:

1)當前的進程數已經達到了系統規定的上限,這時errno的值被設置為EAGAIN。

2)系統內存不足,這時errno的值被設置為ENOMEM。

創建新進程成功后,系統中出現兩個基本完全相同的進程,這兩個進程執行沒有固定的先后順序,哪個進程先執行要看系統的進程調度策略。

對于這種N次循環的情況,執行printf函數的次數為

2*(2^N-1)次,創建的子進程數為2^N-1個。輸出中沒有換行時緩沖區也會被復制

6.程序什么時候使用多線程好,什么時候單線程效率高

1.耗時的操作使用線程,提高應用程序響應速度

2.并行操作時使用線程,如C/S架構的服務器端并發線程響應用戶的請求

3.多CPU系統中,使用線程提高CPU利用率

4.改善程序結構。一個既長又復雜的進程可以考慮分為多個線程,成為幾個獨立或半獨立的運行部分,這樣的程序會利于理解和修改。其他情況都使用單線程。

7.線程間通信

互鎖函數、臨界段、內核對象(事件對象、互斥對象、信號量)

8.進程狀態轉換

在操作系統中,進程一般有三種基本狀態:運行狀態,就緒狀態和等待狀態。

1)就緒——執行:對就緒狀態的進程,當進程調度程序按一種選定的策略從中選中一個就緒進程,為之分配了處理機后,該進程便由就緒狀態變為執行狀態;

2)執行——等待:正在執行的進程因發生某等待事件而無法執行,如進程提出輸入/輸出請求而變成等待外部設備傳輸信息的狀態,進程申請資源(主存空間或外部設備)得不到滿足時變成等待資源狀態,進程運行中出現了故障(程序出錯或主存儲器讀寫錯等)變成等待干預狀態等等;

3)等待——就緒:處于等待狀態的進程,在其等待的事件已經發生,如輸入/輸出完成,資源得到滿足或錯誤處理完畢時,處于等待狀態的進程并不馬上轉入執行狀態,而是先轉入就緒狀態,然后再由系統進程調度程序在適當的時候將該進程轉為執行狀態;

4)執行——就緒:正在執行的進程,因時間片用完而被暫停執行,或在采用搶先式優先級調度算法的系統中,當有更高優先級的進程要運行而被迫讓出處理機時,該進程便由執行狀態轉變為就緒狀態。

9.內存地址:虛擬地址-線性地址-物理地址的區別與聯系

x86平臺下的系統采用分段機制與分頁機制對地址進行轉換,其中分段機制把一個虛擬地址轉換成線性地址;分頁機制把一個線性地址轉換成物理地址

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容