第一部分:线程与队列

线程是代码执行的路径,队列则是用于保存以及管理任务的,线程负责去队列中取任务进行执行。

例如:在主线程调用如下代码

1. dispatch_sync(queue, ^{
2.             task()  
3.         });

可以在task函数中log日志查看

1.  -(void)task
2.  {

3. NSLog(@"1. 当前线程是: %@, 当前队列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue()); 
4.  }

如果将代码改成如下:

1. dispatch_async(queue, ^{
2.             task()  
3.         });

则task函数同样提交到queue队列,但系统会创建辅助线程从queue中取出任务进行执行。



以上粗浅解释了IOS中的线程与队列


第二部分:GCD获取当前队列的方法以及它为何在ios6中被丢弃

1. void func(dispatch_queue_t queue, dispatch_block_t block)  
2. {  
3. if (dispatch_get_current_queue() == queue) {  
4.         block();  
5. else{  
6.         dispatch_sync(queue, block);  
7.     }  
8. } 
9. - (void)deadLockFunc  
10. {  
11. "com.yiyaaixuexi.queueA", NULL);  
12. "com.yiyaaixuexi.queueB", NULL);  
13.     dispatch_sync(queueA, ^{  
14.         dispatch_sync(queueB, ^{  
15.             dispatch_block_t block = ^{  
16. //do something  
17.             };  
18.             func(queueA, block);  
19.         });  
20.     });  
21. }

dispatch_sync将会导致queueA依赖queueB,然而func函数的写法导致queueB也依赖queueA,导致死锁。


那么应该如何保证GCD方法可重入呢?

  • dispatch_queue_set_specific 标记队列

dispatch_get_specific 就是在当前 队列 中取出标识

1. if (dispatch_get_specific(queueKey1)) {  
2. //说明当前的队列就是queue1  
3. }else{  
4. //说明当前的队列不是是queue1  
5. }

再看如下代码可以让你更清晰的理解线程和队列以及

dispatch_get_specific是如何取代dispatch_get_current_queue的 
1. #import <Foundation/Foundation.h>  
2. int main(int argc, const charchar * argv[]) {  
3. @autoreleasepool {  
4. static voidvoid *queueKey1 = "queueKey1";  
5. 1 = dispatch_queue_create(queueKey1, DISPATCH_QUEUE_SERIAL);  
6. 1, queueKey1, &queueKey1, NULL);  
7. @"1. 当前线程是: %@, 当前队列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());  
8. if (dispatch_get_specific(queueKey1)) {  
9. //当前队列是主队列,不是queue1队列,所以取不到queueKey1对应的值,故而不执行  
10. @"2. 当前线程是: %@, 当前队列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());  
11.  sleepForTimeInterval:1];  
12. else{  
13. @"3. 当前线程是: %@, 当前队列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());  
14.  sleepForTimeInterval:1];  
15.         }  
16. 1, ^{  
17. @"4. 当前线程是: %@, 当前队列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());  
18.  sleepForTimeInterval:1];  
19. if (dispatch_get_specific(queueKey1)) {  
20. //当前队列是queue1队列,所以能取到queueKey1对应的值,故而执行  
21. @"5. 当前线程是: %@, 当前队列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());  
22.  sleepForTimeInterval:1];  
23. else{  
24. @"6. 当前线程是: %@, 当前队列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());  
25.  sleepForTimeInterval:1];  
26.             }  
27.         });  
28. 1, ^{  
29. @"7. t当前线程是: %@, 当前队列是: %@ 。",[NSThread currentThread],dispatch_get_current_queue());  
30.  sleepForTimeInterval:1];  
31.         });  
32.  sleepForTimeInterval:5];  
33.     }  
34. return 0;  
35. }

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