GCD全局队列与主队列

GCD默认已经提供了全局的并发队列供整个应用使用,所以可以不用手动创建。

创建全局队列的函数为

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的适配,可以这样创建全局队列:

dispatch_queue_t q = dispatch_get_global_queue(0, 0);

试着用全局队列来做一下异步操作,看看是否为并发执行,如下代码

 dispatch_queue_t q = dispatch_get_global_queue(0, 0);    // 2. 异步执行    for (int i = 0; i < 10; ++i) {        dispatch_async(q, ^{            NSLog(@"%@ %d", [NSThread currentThread], i);        });    }    NSLog(@"come here");

现在我们来模拟一次操作,用户需要先登录之后才能执行两个下载操作,登录和下载都是个耗时操作,所以我们需要在后台开启一条子线程,根据现实情况两个下载操作需要并发执行,那如何实现该需要?借此,我们引出同步函数的作用!有如下代码

// 1. 队列    dispatch_queue_t q = dispatch_get_global_queue(0, 0);       // 2. 任务    void (^task)() = ^ {        dispatch_sync(q, ^{            NSLog(@"Login %@", [NSThread currentThread]);        });        dispatch_async(q, ^{            NSLog(@"Download A %@", [NSThread currentThread]);        });        dispatch_async(q, ^{            NSLog(@"Download B %@", [NSThread currentThread]);        });    };       // 3. 异步执行 task    dispatch_async(q, task);

执行结果如下:

再来一次:

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

在MRC环境下,全局队列不需要释放内存。

当然,GCD本身自带了一种特殊的串行队列,所有放在主队列中的任务都会在主线程上执行。

程序一启动,主线程就已经存在,主队列也同时就存在了,所以主队列不需要创建,只需要获取,如下

 dispatch_queue_t q = dispatch_get_main_queue();

试着在主队列中执行异步任务:

dispatch_queue_t q = dispatch_get_main_queue();       // 2. 异步执行    for (int i = 0; i < 10; ++i) {        dispatch_async(q, ^{            NSLog(@"%@ - %d", [NSThread currentThread], i);        });    }    NSLog(@"线程休眠1s");    [NSThread sleepForTimeInterval:1.0];    NSLog(@"come here - %@",[NSThread currentThread]);

据此可得,主队列中,即使有异步任务,也会依次在主线程上执行,该例子中,主线程上的代码还未执行完,所以异步任务会等主线程上的任务执行完再执行。

那么如果在主线程上执行同步任务会如何呢?如下代码:

// 1.队列    dispatch_queue_tq = dispatch_get_main_queue();    NSLog(@"now I‘m here");    // 2. 同步执行    dispatch_sync(q, ^{        NSLog(@"%@", [NSThreadcurrentThread]);    });    NSLog(@"come here");

程序只执行到第二句代码就无法执行下去了,为什么会这样呢?答案就是主线程被阻塞了,也就是死锁了!!!如果这时候屏幕上有与用户交互的UI,此时也会失去交互功能,像死机了一样!!!

我们都应该清楚,同步任务有一个特性,只要一添加到队列中就要马上执行,主队列中永远就只要一条线程——主线程,此时主线程在等待着主队列调度同步任务,而主队列发现主线程上还有任务未执行完,就不会让同步任务添加到主线程上,由此就造成了互相等待(主队列在等待主线程执行完已有的任务,而主线程又在等待主队列调度同步任务!),此时也就是所谓的死锁了!!!

那么如果有在主队列执行同步任务的需要呢?我们可以用一个异步任务包裹一个同步任务添加到主队列中!如下:

 // 全局队列    dispatch_queue_t q = dispatch_get_global_queue(0, 0);    // 任务    void (^task)() = ^ {        NSLog(@"%@", [NSThread currentThread]);       // 主队列上执行同步任务        dispatch_sync(dispatch_get_main_queue(), ^{            NSLog(@"come here %@", [NSThread currentThread]);        });               NSLog(@"hahaha %@", [NSThread currentThread]);    };       // 异步执行任务    dispatch_async(q, task);    NSLog(@"now i‘m here - %@",[NSThread currentThread]);

执行结果如下:

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

原文地址:http://subscribe.mail.10086.cn/subscribe/readAll.do?columnId=563&itemId=3130310

时间: 2024-08-05 07:06:59

GCD全局队列与主队列的相关文章

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

GCD默认已经提供了全局的并发队列供整个应用使用,所以可以不用手动创建. 创建全局队列的函数为 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,    

1. 关于GCD的使用(串并行队列和同步异步函数的问题)

/*------------------------------ GCD使用 1.队列和任务------------------------------------------*/ 重点:1."串行队列"? "并发队列"? 2.block? { 1.GCD(Grand Central Dispatch) ---- '牛逼的中枢调度器'! // C语言框架 / 自动管理线程的生命周期(创建/释放) 推出GCD的目的:取代NSThread! 为"多核"

IOS 主队列,全局队列的关系

同步,异步,串行,并发 同步和异步代表会不会开辟新的线程.串行和并发代表任务执行的方式. 同步串行和同步并发,任务执行的方式是一样的.没有区别,因为没有开辟新的线程,所有的任务都是在一条线程里面执行. 异步串行和异步并发,任务执行的方式是有区别的,异步串行会开辟一条新的线程,队列中所有任务按照添加的顺序一个一个执行,异步并发会开辟多条线程,至于具体开辟多少条线程,是由系统决定的,但是所有的任务好像就是同时执行的一样. 开辟队列的方法: dispatch_queue_t myQueue = dis

GCD网络多线程---同步执行,异步执行,串行队列,并行队列

总结:同步(不管是串行还是并行)----不开辟子线程 异步(不管是串行还是并行)----开辟子线程 GCD: dispatch queue 主线程的main queue 并行队列 global dispatch queue 串行队列serial queues 一般用于按顺序同步访问 #pragma mark - 加载多线程 - (void) _loadMutil { //GCD基于C语言 //1.主对列:(串行队列) dispatch_queue_t mainQueue=dispatch_get

iOS开发之GCD 多线程 1.串行队列 2.并行队列 3.分组 4.信号量 详细讲解

GCD多线程下,实现线程同步的方式有如下几种: 1.串行队列 2.并行队列 3.分组 4.信号量 实例: 去网上获取一张图片并展示在视图上. 实现这个需求,可以拆分成两个任务,一个是去网上获取图片,一个是展示在视图上. 这两个任务是有关联的,所以需要同步处理. 下面看这几种方式如何实现. 一. 1.串行队列 1.1[GCD相关:] (1)GCD下的dispatch_queue队列都是FIFO队列,都会按照提交到队列的顺序执行. 只是根据队列的性质,分为<1>串行队列:用户队列.主线程队列 &l

ios多线程操作(五)—— GCD串行队列与并发队列

GCD的队列可以分为2大类型,分别为串行队列和并发队列 串行队列(Serial Dispatch Queue): 一次只调度一个任务,队列中的任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务) 创建一个队列 dispatch_queue_t q = dispatch_queue_create(const char *label, dispatch_queue_attr_t attr) 参数: const char *label:队列的名称 dispatch_queue_attr_t

串行队列、并行队列、同步、异步

进程:正在进行中的程序被称为进程,负责程序运行的内存分配;每一个进程都有自己独立的虚拟内存空间 线程:线程是进程中一个独立的执行路径(控制单元);一个进程中至少包含一条线程,即主线程 队列 dispatch_queue_t,队列名称在调试时辅助,无论什么队列和任务,线程的创建和回收不需要程序员操作,有队列负责. 串行队列:队列中的任务只会顺序执行(类似跑步) dispatch_queue_t q = dispatch_queue_create(“....”, dispatch_queue_ser

TCP的SYN队列和Accept队列

首先我们必须明白,处于“LISTENING”状态的TCP socket,有两个独立的队列: SYN队列(SYN Queue) Accept队列(Accept Queue) 这两个术语有时也被称为“reqsk_queue”,“ACK backlog”,“listen backlog”,甚至“TCP backlog”,但是这篇文章中我们使用上面两个术语以免造成混淆. SYN队列 SYN队列存储了收到SYN包的连接(对应内核代码的结构体:struct inet_request_sock).它的职责是回

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型

import java.util.Stack; /**  * 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型.  * @author user  *  *思路:队列是先入先出,栈是先入后出,可以将数据压入第一个栈后,在弹出来压入第二个栈,弹得时候直接从第二个栈弹出,弹出后又将  *第二个栈中的所有数据弹出重新压入的一个栈  */ public class Solution {     Stack<Integer> stack1 = new Stack<