dispatch_after实现原理深度探索

dispatch_after 是GCD中延后执行的一种方法,但是实现原理自己并没有仔细探索过,最近在和群里小伙伴讨论GCD的时候说到dispatch_after,讨论的程序有点复杂,我这里简化为一个for循环来阐述具体实现原理。

示例程序1

1   // 循环5次
2     for (int i =0; i < 5; i++ ) {
3
4         NSLog(@"let‘s go %d",i);
5         // 设置2秒后执行block
6         dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
7             NSLog(@"This is my %d number!",i);
8         });
9     }

程序1运行结果:

 1 2016-01-03 23:55:49.109 dispatchAfterDeep[1095:60579] let‘s go 0
 2 2016-01-03 23:55:49.110 dispatchAfterDeep[1095:60579] let‘s go 1
 3 2016-01-03 23:55:49.111 dispatchAfterDeep[1095:60579] let‘s go 2
 4 2016-01-03 23:55:49.111 dispatchAfterDeep[1095:60579] let‘s go 3
 5 2016-01-03 23:55:49.111 dispatchAfterDeep[1095:60579] let‘s go 4
 6 2016-01-03 23:55:51.111 dispatchAfterDeep[1095:60579] This is my 0 number!
 7 2016-01-03 23:55:51.300 dispatchAfterDeep[1095:60579] This is my 1 number!
 8 2016-01-03 23:55:51.301 dispatchAfterDeep[1095:60579] This is my 2 number!
 9 2016-01-03 23:55:51.301 dispatchAfterDeep[1095:60579] This is my 3 number!
10 2016-01-03 23:55:51.301 dispatchAfterDeep[1095:60579] This is my 4 number!

我们都知道dispatch_after是异步执行它的Block,但是如何异步执行却不知道,先来看下官方文档是如何描述

Declaration
void dispatch_after( dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);

Parameters
when
The temporal milestone returned by dispatch_time or dispatch_walltime.
queue
The queue on which to submit the block. The queue is retained by the system until the block has run to completion. This parameter cannot be NULL.
block
The block to submit. This function performs a Block_copy and Block_release on behalf of the caller. This parameter cannot be NULL.

Discussion
This function waits until the specified time and then asynchronously adds block to the specified queue.

官方文档描述很简洁,翻译过来就是:这个函数等到特定的时间,然后异步添加block到指定的队列中;在示例程序1里面,指定的队列是主队列,也就是当进入循环的时候,会先执行打印了lets go语句,然后异步执行dispatch_after函数,由于内部使用变量来计时,所以“定时器”是设置在了主线程上,等待2秒然后开子线程将Block加入到主队列中,最后主队列按顺序执行Block,但是这样正确吗?

把示例程序的循环次数加到1000次就会发现,Block依然是按顺序执行,但是异步添加Block到主队列肯定不会按顺序添加,主队列又是顺序执行,那么一定会有顺序错误的打印出现,可是继续增加到10000次还是按顺序执行,那么这里dispatch_after函数可能是将添加Block的操作放入一个串行队列,然后在子线程上执行队列,将BLock添加到主队列中,最后主队列执行Block操作。

添加Block部分伪代码如下

1 delay (2){
2
3         dispatch_async(DISPATCH_QUEUE_SERIAL, ^{
4
5             (add block into main queue);
6
7         });
8     }

因为GCD底部细节无法查看,只能逻辑上推断,目前使用以上推断可以顺利解释问题,自己也和小伙伴探讨了很久才确定以上推断,如果有新的发现欢迎交流。

}

时间: 2025-01-13 07:23:01

dispatch_after实现原理深度探索的相关文章

深度探索MySQL主从复制原理

深度探索MySQL主从复制原理 一 .概要 MySQL Replication (MySQL 主从复制) 是什么? 为什么要主从复制以及它的实现原理是什么? 1.1 MySQL 主从复制概念 MySQL 主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点.MySQL 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接上进行,从节点可以复制主数据库中的所有数据库或者特定的数据库,或者特定的表. 1.2 MySQL 主从复制主要用

Pascal Hexagrammum Mysticum 的深度探索

    PASCAL . Hexagrammum Mysticum . (六角迷魂图) . 的深度探索 . 英中对比.英文蓝色,译文黑色,译者补充说明用紫红色 (已校完,但尚未定稿,想再整理并补充内容) keyword:hexagon(六角形.六边形),  6点15边,  45对边交点(opposite edge meet), Hexagrammum  Mysticum(六角迷魂图),  射影几何,   Pascal定理, Pascal线,  Steiner点,   Plucker线,   Ki

Android深度探索(卷一)HAL与驱动开发 第八章

通过学习Android深度探索(卷一)HAL与驱动开发的第八章让我知道了如何让开发板发出声音,如何编写蜂鸣器的驱动程序.了解了Linux驱动的代码重用,代码重用分为静态和动态两种. Linux驱动的代码重用有很多方法,可以采用标准C程序的方式,将重要代码的代码放在其他的文件中,如果要使用某些功能,include相应的头文件即可,这种方式称为静态重用,另外一种动态重用方式就是一个Linux驱动可以使用另一个Linux驱动中的资源. 如果在模拟器或开发板上采用动态装载.ko文件的方式测试Linux驱

Android深度探索(卷1)HAL与驱动开发学习笔记(7)

Android深度探索(卷1)HAL与驱动开发学习笔记(7) 第七章 控制发光二极管   LED驱动实现原理       2. 编写LED驱动 * 创建LED驱动的设备文件 ·使用cdev_init 函数初始化cdev ·指定设备号 ·使用cdev_add函数将字符设备添加到内核中字符设备组中 ·使用class_creat宏创建stuct class ·使用device_creat 创建设备文件 卸载LED驱动的设备文件 依次调用device_destory.class_destory.unre

Android深度探索(卷一)HAL与驱动开发 第七章

通过学习Android深度探索(卷一)HAL与驱动开发的第七章让我了解了如何通过驱动程序来控制发光二极管,实现驱动直接与硬件交互. 一个完整的Linux驱动主要由内部处理和硬件交互两部分组成,其中内部处理主要是指Linux驱动的装载.卸载.与设备文件相关的动作处理以及业务逻辑等:与硬件交互主要是指通过函数与硬件中的寄存器进行数据交互. LED驱动的实现原理:尽管Linux驱动直接与硬件打交道,但并不是Linux驱动直接向硬件中的内存写数据,而是与本机的I/O内存进行交互.每一个连接Linux的硬

Android深度探索HAL与驱动开发 第四章

Android深度探索HAL与驱动开发 第四章 源代码的下载和编译 读书笔记 一.下载编译和测试Android源代码 1.配置Android源代码下载环境 创建一个用于存放下载脚本文件的目录(可将该文件放到任何一个目录在这里使用-/bin) # mkdir ~/bin # PATH=~/bin:$PATH 2.下载repo脚本文件(用于下载Android源代码) # curl htttps://dl-ssl.google.com/dl/googlesource/git-repo/repo> ~/

Android深度探索HAL与驱动开发 第三章

Android深度探索HAL与驱动开发 第三章 Git使用入门 读书笔记 Git是对源代码进行管理的软件. 一.安装Git # apt-get install git # apt-get install git-doc git-emall git-gui gitk 用以下命令控制Git: # apt-get install git-core # apt-get install git-doc git-svn git-email git-gui gitk 二.查看Git文档 查看git-check

Android深度探索(卷1)HAL与驱动开发学习笔记(2)

Android深度探索(卷1)HAL与驱动开发学习笔记(2) 第二章搭建Android开发环境 书中介绍了两种JDK的安装方法, 方法一: 从官网下载JDK并进行配置,解压后在终端打开profile文件来设置PATH环境变量(# soure /etc/profile),打开profile文件后输入下面的内容 export PATH=.:developer/jdk6/bin:$PATH 保存profile文件以后,有两种方法可以重新加载profile文件. 1.# sourse  /etc/pro

深度探索C++对象模型的读书心得

参考:深度探索C++对象模型 (stanley B.Lippman著 侯捷翻译) 1. Page9 : C++对象模型,说明每一个类仅有一个虚函数表Vtbl,而类的每一个对象都有指向其表的指针. 2. Page30:引用也需要与一个指针(大小为4BYTE)相同的空间. 3. Page28: 指针类型会教导编译器如何解释某个特定地址中的内存内容及大小. 4. Page39: explicit关键字能够制止"单一参数的constructor被当做一个Conversion运算符" 5. Pa