iOS 多線程
經常聽到這樣的問題 "你在處理多線程的時候 遇到過什么問題 或者說 你使用過多線程嗎 如何操作的"
具體 我也沒聽過 別人是怎么回答的,我也沒太想好怎樣回答才算全面,今天利用工作空余時間好好系統學一下,從以下幾個角度學習
1 理論
2 舉例子運用
3 實際開發注意要點
一 理論
1 線程和進程
a 一般運行一個程序就是一個進程. 一個程序至少有一個進程,一個進程至少有一個線程
b 線程,是進程的一部分,一個沒有線程的進程可以被看作是單線程的 (相對進程而言,線程是一個更加接近于執行體的概念)
c 進程可以創建線程 也可以創建進程
d 線程由進程管理, 線程之間 線程和父進程之間(創建線程的進程)共享內存變量 (需要策略實現)
e 進程之間一般不可以直接共享內存變量,需要一些進程間的控制共享內存變量
2 iOS 多線程編程技術(這里主講GCD)
NSThread NSOperation GCD
(1) NSThread
優點: 使用起來比 其他兩個更輕量級
缺點:需要自己管理線程的生命周期,線程同步. 線程同步的加鎖會又一定的系統開銷
(2)NSOperation
優點:無需關心線程管理,數據同步.關鍵是操作執行操作.
相關類:抽象類 NSInvocationOperation 和 NSBlockOperation
創建NSOperation子類對象,把對象添加到NSOperationqueue隊列里執行
(3)GCD (grand central dispatch)
iOS4后開始使用,是代替以上兩種多線程方法的強大技術,GCD中FIFO隊列稱為 dispatch queue
dispatch queue :
a 串行隊列: serial 隊列 隊里任務 是一個一個地執行
dispatch_queue_t queue = dispatch_queue_create("com.xxx.serialQueue",DISPATCH_QUEUE_SERIAL);// 自己創建一個串行隊列
b 并行隊列:concurrent 隊列 通常任務會并發的執行
dispatch_queue_t queue = dispatch_queue_create("com.xxx.concurrentQueue",DISPATCH_QUEUE_CONCURRENT);// 自己創建一個并行隊列
c 全局隊列 : 系統級別的,直接拿來用,是一種并發隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
d 主隊列 :一個應用程序對應唯一一個主隊列,也是系統級別,直接拿來用,多線程開發使用主隊列更新UI. 是一種串行隊列
dispatch_queue_t queue = dispatch_get_main_queue();
二 舉例運用
dispatch queue
#define global_queue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
#define main_queue dispatch_get_main_queue()
(1)dispatch_async
耗時懂得操作,數據處理,IO讀取數據庫什么的 在另一個線程中處理,然后通知主線程更新UI
常用方法:
dispatch_async(global_queue, ^{ //耗時間性能的處理放在這 dispatch_sync(main_queue, ^{ //主線程更新UI }); });
(2)dispatch_group_async
可以實現監聽一組任務是否完成, 完成后得到通知再執行其他操作
常用方法舉例:下載 5張圖片(或者說有五個獨立數據請求),下載完了更新UI (都請求完成后執行其他操作)
- (void)fun { // 創建一個組 dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, global_queue, ^{ //開啟一個任務1 }); dispatch_group_async(group, global_queue, ^{ // 開啟一個任務2 });
//開啟一個任務3
//開啟一個任務4
//開啟一個任務5
dispatch_group_notify(group, main_queue, ^{
// 等group中的所有任務都執行完畢, 再回到主線程執行其他操作 }); }
(3)dispathch_barrier_async(柵欄函數)
void dispatch_barrier_async ( dispatch_queue_t queue, dispatch_block_t block );
參數 queue: 將barrier添加到那個隊列
block: barrier block 代碼塊
"在它前面的的任務執行后它才執行,在它后面的任務需要等它執行完成后才能執行".
使用情況是和并行隊列一起使用,"同dispatch_queue_create函數生成的concurrent Dispatch Queue隊列一起使用", 這個queue 一定是 自己創建的 并發隊列,如果是 使用全局并發隊列或者是一個串行隊列,那么這個函數等同于dispatch_async函數.
使用舉例:
- (void)barrier { dispatch_queue_t queue = dispatch_queue_create("myConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);//這個queue 一定是 自己創建的 并發隊列,如果是 使用全局并發隊列或者是一個串行隊列,那么這個函數等同于dispatch_async函數. dispatch_async(queue, ^{ NSLog(@"任務1"); }); dispatch_async(queue, ^{ NSLog(@"任務2"); }); dispatch_barrier_async(queue, ^{ NSLog(@"barrier"); }); dispatch_async(queue, ^{ NSLog(@"任務3"); }); dispatch_async(queue, ^{ NSLog(@"任務4"); }); }
打印結果
任務1
任務2 (1 和 2 并發 順序不定)
barrier
任務3
任務4 (3 和 4 并發 順序不定)
(4)dispatch_apply
執行N次的某一個代碼片段
dispatch_apply(5, global_queue, ^(size_t index){ //此處任務執行5次 });
三 實際開發注意要點
重點是關注多線程死鎖問題,和正確選擇多線程策略
關于死鎖,主要參考大學操作系統課程標配講解:
死鎖原因
(1)資源競爭 資源分配不當
(2)系統資源不足
(3)進程運行推進順序不合適
死鎖條件:
(1)互斥:進程在某一時間內獨占資源
(2)請求與保持:進程已經擁有當前資源,但是又申請新資源
(3)不可剝奪: 進程的資源沒使用完 就不可以強行從資源占有者處爭奪資源
(4)循環等待 : 出現閉環
死鎖預防:(破壞上述四個必要條件的一個或者幾個)
(1)破壞上述四個必要條件的一個或者幾個 來防止死鎖產生
(2)鴕鳥算法,發生錯誤概率極小 可忽略
(3)仔細檢查對資源的動態分配情況,來預防死鎖
(4)檢測死鎖并且恢復
(5)避免死鎖的一個通用的經驗法則是:當幾個線程都要訪問共享資源A、B、C時,保證使每個線程都按照同樣的順序去訪問它們,比如都先訪問A,在訪問B和C。這樣不會產生閉環.
參考:
https://developer.apple.com/reference/dispatch#//apple_ref/c/func/dispatch_barrier_async
posted on 2016-11-18 11:34 ACM_Someone like you 閱讀(379) 評論(0) 收藏 舉報
浙公網安備 33010602011771號