ios多线程操作(六)—— GCD全局队列与主队列

GCD默认已经提供了全局的并发队列供整个应用使用,所以可以不用手动创建。
      创建全局队列的函数为
[objc]  view plain  copy
 
  1. dispatch_queue_t q = dispatch_get_global_queue(long identifier, unsigned long flags)  

  参数类型为:
long identifier:ios 8.0 告诉队列执行任务的“服务质量 quality of service”,系统提供的参数有:

     QOS_CLASS_USER_INTERACTIVE 0x21,              用户交互(希望尽快完成,用户对结果很期望,不要放太耗时操作)
     QOS_CLASS_USER_INITIATED 0x19,                用户期望(不要放太耗时操作)
     QOS_CLASS_DEFAULT 0x15,                       
 默认(不是给程序员使用的,用来重置对列使用的)
     QOS_CLASS_UTILITY 0x11,                       
 实用工具(耗时操作,可以使用这个选项)
     QOS_CLASS_BACKGROUND 0x09,                    
 后台
     QOS_CLASS_UNSPECIFIED 0x00,                   
 未指定
     iOS 7.0
 之前 优先级
     DISPATCH_QUEUE_PRIORITY_HIGH 2                
 高优先级
     DISPATCH_QUEUE_PRIORITY_DEFAULT 0             
 默认优先级
     DISPATCH_QUEUE_PRIORITY_LOW (-2)              
 低优先级
     DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN  后台优先级

    BACKGROUND表示用户不需要知道任务什么时候完成,如果选择这个选项速度慢得令人发指,非常不利于调试!对于优先级推荐不要搞得太负责,就用最简单,以免发生优先级反转。
     
    unsigned long flags:苹果官方文档是这样解释的: Flags that are reserved for future use。标记是为了未来使用保留的!所以这个参数应该永远指定为0
   如果做ios8.0与ios7.0的适配,可以这样创建全局队列:
[objc]  view plain  copy
 
  1. dispatch_queue_t q = dispatch_get_global_queue(00);  
   试着用全局队列来做一下异步操作,看看是否为并发执行,如下代码
[objc]  view plain  copy
 
  1. dispatch_queue_t q = dispatch_get_global_queue(00);  
  2.    // 2. 异步执行  
  3.    for (int i = 0; i < 10; ++i) {  
  4.        dispatch_async(q, ^{  
  5.            NSLog(@"%@ %d", [NSThread currentThread], i);  
  6.        });  
  7.    }  
  8.    NSLog(@"come here");  


运行结果如下:

验证正确
     现在我们来模拟一次操作,用户需要先登录之后才能执行两个下载操作,登录和下载都是个耗时操作,所以我们需要在后台开启一条子线程,根据现实情况两个下载操作需要并发执行,那如何实现该需要?借此,我们引出同步函数的作用!有如下代码
[objc]  view plain  copy
 
  1. // 1. 队列  
  2.     dispatch_queue_t q = dispatch_get_global_queue(00);  
  3.      
  4.     // 2. 任务  
  5.     void (^task)() = ^ {  
  6.         dispatch_sync(q, ^{  
  7.             NSLog(@"Login %@", [NSThread currentThread]);  
  8.         });  
  9.         dispatch_async(q, ^{  
  10.             NSLog(@"Download A %@", [NSThread currentThread]);  
  11.         });  
  12.         dispatch_async(q, ^{  
  13.             NSLog(@"Download B %@", [NSThread currentThread]);  
  14.         });  
  15.     };  
  16.      
  17.     // 3. 异步执行 task  
  18.     dispatch_async(q, task);  


执行结果如下:

再来一次:

结果无论如何都是在子线程上执行,而且登录永远都在最前面,至于哪条线程先下载我们不得而知,以上结果只是简单展示,如果开多下载基本书就可以展示更好的效果,这里就不演示了。
     在MRC环境下,全局队列不需要释放内存。

     当然,GCD本身自带了一种特殊的串行队列,所有放在主队列中的任务都会在主线程上执行。
     程序一启动,主线程就已经存在,主队列也同时就存在了,所以主队列不需要创建,只需要获取,如下
[objc]  view plain  copy
 
  1. dispatch_queue_t q = dispatch_get_main_queue();  
试着在主队列中执行异步任务:
[objc]  view plain  copy
 
  1. dispatch_queue_t q = dispatch_get_main_queue();  
  2.      
  3.     // 2. 异步执行  
  4.     for (int i = 0; i < 10; ++i) {  
  5.         dispatch_async(q, ^{  
  6.             NSLog(@"%@ - %d", [NSThread currentThread], i);  
  7.         });  
  8.     }  
  9.     NSLog(@"线程休眠1s");  
  10.     [NSThread sleepForTimeInterval:1.0];  
  11.     NSLog(@"come here - %@",[NSThread currentThread]);  

执行的结果如下:

据此可得,主队列中,即使有异步任务,也会依次在主线程上执行,该例子中,主线程上的代码还未执行完,所以异步任务会等主线程上的任务执行完再执行。
     那么如果在主线程上执行同步任务会如何呢?如下代码:
[objc]  view plain  copy
 
  1. // 1.队列  
  2.     dispatch_queue_tq = dispatch_get_main_queue();  
  3.     NSLog(@"now I'm here");  
  4.     // 2. 同步执行  
  5.     dispatch_sync(q, ^{  
  6.         NSLog(@"%@", [NSThreadcurrentThread]);  
  7.     });  
  8.     NSLog(@"come here");  


此时打印台打印出来的结果如下
程序只执行到第二句代码就无法执行下去了,为什么会这样呢?答案就是主线程被阻塞了,也就是死锁了!!!如果这时候屏幕上有与用户交互的UI,此时也会失去交互功能,像死机了一样!!!
     我们都应该清楚,同步任务有一个特性,只要一添加到队列中就要马上执行,主队列中永远就只要一条线程——主线程,此时主线程在等待着主队列调度同步任务,而主队列发现主线程上还有任务未执行完,就不会让同步任务添加到主线程上,由此就造成了互相等待(主队列在等待主线程执行完已有的任务,而主线程又在等待主队列调度同步任务!),此时也就是所谓的死锁了!!!
     那么如果有在主队列执行同步任务的需要呢?我们可以用一个异步任务包裹一个同步任务添加到主队列中!如下:
[objc]  view plain  copy
 
  1. // 全局队列  
  2.    dispatch_queue_t q = dispatch_get_global_queue(00);  
  3.    // 任务  
  4.    void (^task)() = ^ {  
  5.        NSLog(@"%@", [NSThread currentThread]);  
  6.       // 主队列上执行同步任务  
  7.        dispatch_sync(dispatch_get_main_queue(), ^{  
  8.            NSLog(@"come here %@", [NSThread currentThread]);  
  9.        });  
  10.         
  11.        NSLog(@"hahaha %@", [NSThread currentThread]);  
  12.    };  
  13.     
  14.    // 异步执行任务  
  15.    dispatch_async(q, task);  
  16.    NSLog(@"now i'm here - %@",[NSThread currentThread]);  


执行结果如下:

主线程没有被阻塞!!!"now i'm here“出现的位置不确定,但总会先于主队列中的同步函数!主队列的同步任务被添加到全局队列的异步任务中,全局队列会先让主线程上的任务先执行完再执行同步任务!

你可能感兴趣的:(ios多线程操作(六)—— GCD全局队列与主队列)