1. 程式人生 > >IOS對於執行緒佇列的一些理解

IOS對於執行緒佇列的一些理解

第一部分:執行緒與佇列

執行緒是程式碼執行的路徑,佇列則是用於儲存以及管理任務的,執行緒負責去佇列中取任務進行執行。

例如:在主執行緒呼叫如下程式碼

  1. dispatch_sync(queue, ^{
  1.             task()  
  1.         }); 
可以在task函式中log日誌檢視
  1. -(void)task
  1. {
  1. NSLog(@"1. 當前執行緒是: %@, 當前佇列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue()); 
  1. }
如果將程式碼改成如下:
  1. dispatch_async(queue, ^{
  1.             task()  
  1.         }); 
則task函式同樣提交到queue佇列,但系統會建立輔助執行緒從queue中取出任務進行執行。以上粗淺解釋了IOS中的執行緒與佇列第二部分:GCD獲取當前佇列的方法以及它為何在ios6中被丟棄
  1. void func(dispatch_queue_t queue, dispatch_block_t block)  
  1. {  
  1.     if (dispatch_get_current_queue() == queue) {  
  1.         block();  
  1.     }else{  
  1.         dispatch_sync(queue, block);  
  1.     }  
  1. - (void)deadLockFunc  
  1. {  
  1.     dispatch_queue_t queueA = dispatch_queue_create("com.yiyaaixuexi.queueA"NULL);  
  1.     dispatch_queue_t queueB = dispatch_queue_create("com.yiyaaixuexi.queueB"NULL);  
  1.     dispatch_sync(queueA, ^{  
  1.         dispatch_sync(queueB, ^{  
  1.             dispatch_block_t block = ^{  
  1.                 //do something
  1.             };  
  1.             func(queueA, block);  
  1.         });  
  1.     });  
  1. }  
dispatch_sync將會導致queueA依賴queueB,然而func函式的寫法導致queueB也依賴queueA,導致死鎖。
那麼應該如何保證GCD方法可重入呢?
  • dispatch_queue_set_specific 標記佇列
dispatch_get_specific就是在當前佇列中取出標識
  1. if (dispatch_get_specific(queueKey1)) {  
  1.     //說明當前的佇列就是queue1
  1. }else{  
  1.     </span>//說明當前的佇列不是是queue1
  1. }  
再看如下程式碼可以讓你更清晰的理解執行緒和佇列以及dispatch_get_specific是如何取代dispatch_get_current_queue的
  1. #import <Foundation/Foundation.h>
  1. int main(int argc, constcharchar * argv[]) {  
  1.     @autoreleasepool {  
  1.         staticvoidvoid *queueKey1 = "queueKey1";  
  1.         dispatch_queue_t queue1 = dispatch_queue_create(queueKey1, DISPATCH_QUEUE_SERIAL);  
  1.         dispatch_queue_set_specific(queue1, queueKey1, &queueKey1NULL);  
  1.         NSLog(@"1. 當前執行緒是: %@, 當前佇列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());  
  1.         if (dispatch_get_specific(queueKey1)) {  
  1.             //當前佇列是主佇列,不是queue1佇列,所以取不到queueKey1對應的值,故而不執行
  1.             NSLog(@"2. 當前執行緒是: %@, 當前佇列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());  
  1.             [NSThread sleepForTimeInterval:1];  
  1.         }else{  
  1.             NSLog(@"3. 當前執行緒是: %@, 當前佇列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());  
  1.             [NSThread sleepForTimeInterval:1];  
  1.         }  
  1.         dispatch_sync(queue1, ^{  
  1.             NSLog(@"4. 當前執行緒是: %@, 當前佇列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());  
  1.             [NSThread sleepForTimeInterval:1];  
  1.             if (dispatch_get_specific(queueKey1)) {  
  1.                  //當前佇列是queue1佇列,所以能取到queueKey1對應的值,故而執行
  1.                 NSLog(@"5. 當前執行緒是: %@, 當前佇列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());  
  1.                 [NSThread sleepForTimeInterval:1];  
  1.             }else{  
  1.                 NSLog(@"6. 當前執行緒是: %@, 當前佇列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());  
  1.                 [NSThread sleepForTimeInterval:1];  
  1.             }  
  1.         });  
  1.         dispatch_async(queue1, ^{  
  1.             NSLog(@"7. t當前執行緒是: %@, 當前佇列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());  
  1.             [NSThread sleepForTimeInterval:1];  
  1.         });  
  1.         [NSThread sleepForTimeInterval:5];  
  1.     }  
  1.     return0;  
  1. }  

task函式這個任務將會提交到佇列queue上,主執行緒負責去執行這個任務。

dispatch_get_current_queue這個方法可以很方便的獲取到當前執行緒,可為什麼要丟棄這個函式呢?請看一下程式碼

為了防止類似的誤用,蘋果在iOS6廢棄了dispatch_get_current_queue()方法。強大的dispatch_get_current_queue()也只能當作一個除錯工具了。

dispatch_queue_set_specific就是向指定佇列裡面設定一個標識 如:

dispatch_queue_set_specific(queue1, queueKey1, &queueKey1,NULL);

就是向queue1對了中設定一個queueKey1標識。

輸出結果:

2016-02-19 14:31:23.390 gcd[96865:820267] 1.當前執行緒是: <NSThread: 0x1001053e0>{number = 1, name = main},當前佇列是: <OS_dispatch_queue: com.apple.main-thread[0x100059ac0]>

2016-02-19 14:31:23.391 gcd[96865:820267] 3.當前執行緒是: <NSThread: 0x1001053e0>{number = 1, name = main},當前佇列是: <OS_dispatch_queue: com.apple.main-thread[0x100059ac0]>

2016-02-19 14:31:24.396 gcd[96865:820267] 4.當前執行緒是: <NSThread: 0x1001053e0>{number = 1, name = main},當前佇列是: <OS_dispatch_queue: queueKey1[0x103000000]>

2016-02-19 14:31:25.400 gcd[96865:820267] 5.當前執行緒是: <NSThread: 0x1001053e0>{number = 1, name = main},當前佇列是: <OS_dispatch_queue: queueKey1[0x103000000]>

2016-02-19 14:31:26.402 gcd[96865:820367] 7. t當前執行緒是: <NSThread: 0x100105e10>{number = 2, name = (null)},當前佇列是: <OS_dispatch_queue: queueKey1[0x103000000]>

Program ended with exit code: 0