一、什么是GCD?

以下是摘自苹果的官方说明。

Grand Central Dispatch(GCD)是异步执行任务的技术之一。一般将应用程序中记述的线程管理用的代码在系统级中实现。开发者只需要定义想执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务。

二、GCD实现之Dispatch Queue

  • 用于管理追加的Block的C语言层实现的FIFO队列
  • Atomic函数中实现的用于排他控制的轻量级信号
  • 用于管理线程的C语言层实现的一些容器

GCD的API全部包含在libdispatch库中的C语言函数。Dispatch Queue通过结构体和链表,被实现为FIFO队列。FIFO队列管理是通过dispatch_async等函数所追加的Block。

Block并不是直接加入FIFO队列,而是先加入Dispatch Continuation这一dispatch_continution_t类结构体中,然后再加入FIFO队列。该Dispatch Continuation用于记忆Block所属的Dispatch Group和其他一些信息,相当于一般常说的执行上下文。

Dispatch Queue可通过dispatch_set_target_queue函数设定,可以设定执行该Dispatch Queue处理的Dispatch Queue为目标。该目标可像串珠子一样,设定多个连接在一起的Dispatch Queue。但是在连接串的最后必须设定为Main Dispatch Queue,或各种优先级的Global Dispatch Queue,或是准备用于Serial Dispatch Queue的各种优先级的 Global Dispatch Queue.

Global Dispatch Queue有如下8种。

  • Global Dispatch Queue (High Priority)
  • Global Dispatch Queue (Default Priority)
  • Global Dispatch Queue (Low Priority)
  • Global Dispatch Queue (Background Priority)
  • Global Dispatch Queue (High Overcommit Priority)
  • Global Dispatch Queue (Default Overcommit Priority)
  • Global Dispatch Queue (Low Overcommit Priority)
  • Global Dispatch Queue (Background Overcommit Priority)

优先级中附有Overcommit的Global Dispatch Queue使用在Serial Dispatch Queue中。如Overcommit这个名称所示,不管系统状态如何,都会强制生成线程的Dispatch Queue。

这8种Global Dispatch Queue各使用1个pthread_workqueue。GCD初始化时,使用pthread_workqueue_create_np函数生成pthread_workqueue。

pthread_workqueue包含在Libc提供的pthreads API中。其使用bsdthread_register和workq_open系统调用,在初始化XNU内核的workqueue之后获取workqueue信息。

XNU内核持有4中workqueue。

  • WORKQUEUE_HIGH_PRIOQUEUE
  • WORKQUEUE_DEFAULT_PRIOQUEUE
  • WORKQUEUE_LOW_PRIOQUEUE
  • WORKQUEUE_BG_PRIOQUEUE

以上为4种执行优先级的workqueue。该执行优先级与Global Dispatch Queue的4种执行优先级相同。

Dispatch Queue中执行Block的过程。

当在Global Dispatch Queue中执行Block时,libdispatch从Global Dispatch Queue自身的FIFO队列中取出Dispatch Continuation,调用pthread_workqueue_additem_np函数。将该Global Dispatch Queue自身、符合其优先级的workqueue信息以及为执行Dispatch Continuation的回调函数等传递给参数。

pthread_workqueue_additem_np函数使用workq_kernreturn系统调用,通知workqueue增加应当执行的项目。根据该通知,XNU内核基于系统状态判断是否需要生成线程。如果是Overcommit优先级的Global Dispatch Queue,workqueue则始终生成线程。

workqueue的线程执行pthread_workqueue函数,该函数调用libdispatch的回调函数。在该回调函数中执行加入到Dispatch Continuation的Block。

Block执行结束后,进行通知Dispatch Group结束、释放Dispatch Continuation等处理,开始准备执行加入到Global Dispatch Queue中的下一个Block。

以上就是Dispatch Queue执行的大概过程。

三、线程和队列

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

1、队列

是管理线程的,相当于线程池,能管理线程什么时候执行。

队列分为串行队列和并行队列等

串行队列:队列中的任务按顺序执行

并行队列:队列中的任务会并发执行。任务执行完毕了,不一定出队列。只有前面的任务执行完了,才会出队列。

串行队列:队列中的任务只会顺序执行,多个串行队列可并行执行

dispatch_queue_t q = dispatch_queue_create(“xxx”,DISPATCH_QUEUE_SERIAL);

并行队列:队列中的任务会并发执行

dispatch_queue_t q = dispatch_queue_create(“xxx”, DISPATCH_QUEUE_CONCURRENT);

全局队列:与并行队列类似,但调试时,无法确认操作所在队列

dispatch_queue_t q = dispatch_get_global_queue(dispatch_queue_priority_default, 0);

主队列:每一个程序对应唯一一个主队列;在多线程开发中,使用主队列更新UI

dispatch_queue_t q = dispatch_get_main_queue();

2、同步和异步

dispatch_async (异步操作函数),就是将指定的Block“非同步”地追加到指定的队列(queue)中。dispatch_async函数不做任何等待。会新开线程

dispatch_sync( 同步操作函数),就是将指定的Block“同步”地追加到指定的队列(queue)中。在追加Block结束之前,dispatch_sync函数会一直等待;不会新开线程

3、队列和操作的组合

串行队列同步操作:同步操作不会新开线程、操作顺序执行

串行队列异步操作:异步操作新开一个子线程、操作顺序执行,“最安全的选择”

并行队列同步操作:同步操作不会新开线程、操作顺序执行

并行队列异步操作:异步操作会新开多个线程(有多少任务,就开n个线程执行)、操作无序执行;队列前如果有其他任务,会等待前面的任务完成之后再执行;场景:既不影响主线程,又不需要顺序执行的操作!

全局队列异步操作:异步操作会新建多个线程、操作无序执行,队列前如果有其他任务,会等待前面的任务完成之后再执行

全局队列同步操作:同步操作不会新建线程、操作顺序执行

主队列异步操作:异步操作都在主线程上顺序执行的,不存在异步的概念

主队列同步操作:会死锁

4、会引起死锁的2种情况

1、在主线程中运用主队列同步。

- (void)viewDidLoad {

[super viewDidLoad];

dispatch_sync(dispatch_get_main_queue(), ^{

NSLog(@"hello");

});

}

同步对于任务是立刻执行的,那么当把任务放进主队列时,它就会立马执行,只有执行完这个任务,viewDidLoad才会继续向下执行。

而viewDidLoad和任务都是在主队列上的,由于队列的先进先出原则,任务又需等待viewDidLoad执行完毕后才能继续执行,viewDidLoad和这个任务就形成了相互循环等待,就造成了死锁。

想避免这种死锁,可以将同步改成异步dispatch_async,或者将dispatch_get_main_queue换成其他串行或并行队列,都可以解决。

2、在串行队列中同步的向这个串行队列追加Block

dispatch_queue_t serialQueue = dispatch_queue_create("xxx", DISPATCH_QUEUE_SERIAL);

dispatch_async(serialQueue, ^{

dispatch_sync(serialQueue, ^{

NSLog(@"hello");

});

});

想避免这种死锁,可以将同步改成异步dispatch_async,或者将串行队列换为并行队列,都可以解决。

以上部分内容参考自《Objective-C高级编程》一书

GCD之队列的实现和使用的更多相关文章

  1. iOS边练边学--GCD的基本使用、GCD各种队列、GCD线程间通信、GCD常用函数、GCD迭代以及GCD队列组

    一.GCD的基本使用 <1>GCD简介 什么是GCD 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数   GCD的优势 G ...

  2. ios线程和GCD和队列同步异步的关系

    1.什么是进程? 进程是指在系统中正在运行的一个应用程序.比如同时打开QQ.Xcode,系统就会分别启动2个进程.截图 2.什么是线程? 1).一个进程要想执行任务,必须得有线程(每一个进程至少要有一 ...

  3. iOS 关于GCD中的队列

    GCD中队列分类及获得方式 1.串行队列  dispatch_queue_t queue = dispatch_queue_create("队列名", DISPATCH_QUEUE ...

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

          GCD的队列能够分为2大类型,分别为串行队列和并发队列      串行队列(Serial Dispatch Queue):      一次仅仅调度一个任务,队列中的任务一个接着一个地运行( ...

  5. AJ学IOS(50)多线程网络之GCD简单介绍(任务,队列)

    AJ分享,必须精品 GCD简单介绍 1.什么是GCD? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD的优势 GCD是苹果 ...

  6. iOS 多线程GCD简介

    一.简介 1.1 GCD (Grand Central Dispatch )是Apple开发的一个多核编程的解决方法. Grand 含义是“伟大的.宏大的”,Central含义“中央的”,Dispat ...

  7. iOS GCD 编程小结

    一.简单介绍 1.GCD简介? 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 2.GCD优势 GCD是苹果公司为多核的并行运算提出的 ...

  8. GCD: 基本概念和Dispatch Queue 【转】

    什么是GCD? Grand Central Dispatch或者GCD,是一套低层API,提供了一种新的方法来进行并发程序编写.从基本功能上讲,GCD有点像 NSOperationQueue,他们都允 ...

  9. IOS 多线程02-pthread 、 NSThread 、GCD 、NSOperationQueue、NSRunLoop

    注:本人是翻译过来,并且加上本人的一点见解. 要点: 1.前言 2.pthread 3.NSThread 4.Grand Central Dispatch(GCD) 5.Operation Queue ...

随机推荐

  1. LeetCode707 设计链表

    设计链表的实现.您可以选择使用单链表或双链表.单链表中的节点应该具有两个属性:val 和 next.val 是当前节点的值,next 是指向下一个节点的指针/引用.如果要使用双向链表,则还需要一个属性 ...

  2. MySQL select 查询之分组和过滤

    SELECT 语法 SELECT [ALL | DISTINCT] {* | table.* | [table.field1[as alias1][,table.field2[as alias2]][ ...

  3. Error: Could not request certificate: No route to host - connect(2)

    [root@puppetclient ~]# puppet agent --server 192.168.127.137 --testInfo: Creating a new SSL key for ...

  4. 分别使用 Python 和 Math.Net 调用优化算法

    1. Rosenbrock 函数 在数学最优化中,Rosenbrock 函数是一个用来测试最优化算法性能的非凸函数,由Howard Harry Rosenbrock 在 1960 年提出 .也称为 R ...

  5. 【Linux】ABRT has detected 1 problem(s). For more info run: abrt-cli list --since 1548988705

    ------------------------------------------------------------------------------------------------- | ...

  6. 【RAC】安装cluster软件 在节点2执行root.sh脚本

    安装cluster软件  在节点2执行root.sh脚本 报错如下: Running vipca(silent) for configuring nodeapps /db/oracle/product ...

  7. 使用NIM Server网络半自动安装AIX系统

    一.NIM配置 1.安装NIMServer前准备 1.1.配置IP地址 # ifconfig –a #检查当前IP地址# # smitty mktcpip #设置IP地址# 选择第一块网卡(插网线的网 ...

  8. JS实现计算器,带三角函数,根号

    极简主义网页计算器. 实现了按键特效,可响应键盘按键,实时显示计算结果. 可切换模式,拓展高级功能,包括根号.三角函数.括号等. 效果如下: 代码如下: html: <!DOCTYPE html ...

  9. Less中Css预处理器

    Less.js 安装 npm install -g less 变量 basic 变量采用@进行变量定义.变量可以直接参加运算. @width:100px; .variables{ width:@wid ...

  10. mysql的安装使用及其用户管理

    mysql的安装使用及其用户管理   一.mariadb安装 搭建yum源 [mariadb] name = MariaDB baseurl = http://mirrors.ustc.edu.cn/ ...