GCD多线程的使用(四)

关于dispatch_set_target_queue和dispatch_after的使用。

使用GCD的函数dispatch_queue_create创建的Dispatch Queue(Serial Dispatch Queue和Concurrent Dispatch Queue)使用的优先级都是默认优先级,有时根据需求可能会变更优先级,变更优先级要使用dispatch_set_target_queue函数。下面是创建一个低优先级的Serial Dispatch Queue示例:

/**
 *  创建一个低优先级的Serial Dispatch Queue
 */
- (void)createLowPrioritySerialDispatchQueue {
    dispatch_queue_t queue = dispatch_queue_create("com.hxp.queue", DISPATCH_QUEUE_SERIAL);  //此时的优先级为默认优先级
    dispatch_queue_t targetQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0); //创建一个低优先级的目标Global Dispatch Queue
    dispatch_set_target_queue(queue, targetQueue);  //更改优先级为目标Dispatch Queue的优先级
}

dispatch_set_target_queue函数的第一个参数是需要变更优先级的Dispatch Queue,第二个参数是指定要使用的执行优先级相同优先级的Global Dispatch Queue,即目标Dispatch Queue。

另外,dispatch_set_target_queue函数还有指定执行顺序的功能呢,先看代码和输出结果:

    dispatch_queue_t queue0 = dispatch_queue_create("com.hxp.queue0", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue1 = dispatch_queue_create("com.hxp.queue1", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue2 = dispatch_queue_create("com.hxp.queue2", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue3 = dispatch_queue_create("com.hxp.queue3", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue4 = dispatch_queue_create("com.hxp.queue4", DISPATCH_QUEUE_SERIAL);

    dispatch_async(queue0, ^{
        NSLog(@"%@:queue0", [NSThread currentThread]);
    });
    dispatch_async(queue1, ^{
        NSLog(@"%@:queue1", [NSThread currentThread]);
    });
    dispatch_async(queue2, ^{
        NSLog(@"%@:queue2", [NSThread currentThread]);
    });
    dispatch_async(queue3, ^{
        NSLog(@"%@:queue3", [NSThread currentThread]);
    });
    dispatch_async(queue4, ^{
        NSLog(@"%@:queue4", [NSThread currentThread]);
    });

正常的输出结果应该是顺序杂乱无章,并发执行:

2015-06-19 07:01:12.885 GCD_Study[23054:3603] {name = (null), num = 6}:queue4
2015-06-19 07:01:12.885 GCD_Study[23054:1303] {name = (null), num = 2}:queue0
2015-06-19 07:01:12.885 GCD_Study[23054:3403] {name = (null), num = 5}:queue2
2015-06-19 07:01:12.885 GCD_Study[23054:3503] {name = (null), num = 3}:queue3
2015-06-19 07:01:12.885 GCD_Study[23054:3107] {name = (null), num = 4}:queue1

然后使用dispatch_set_target_queue函数指定优先级后:

    dispatch_queue_t queue0 = dispatch_queue_create("com.hxp.queue0", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue1 = dispatch_queue_create("com.hxp.queue1", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue2 = dispatch_queue_create("com.hxp.queue2", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue3 = dispatch_queue_create("com.hxp.queue3", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue4 = dispatch_queue_create("com.hxp.queue4", DISPATCH_QUEUE_SERIAL);

    dispatch_set_target_queue(queue1, queue0);
    dispatch_set_target_queue(queue2, queue0);
    dispatch_set_target_queue(queue3, queue0);
    dispatch_set_target_queue(queue4, queue0);

    dispatch_async(queue0, ^{
        NSLog(@"%@:queue0", [NSThread currentThread]);
    });
    dispatch_async(queue1, ^{
        NSLog(@"%@:queue1", [NSThread currentThread]);
    });
    dispatch_async(queue2, ^{
        NSLog(@"%@:queue2", [NSThread currentThread]);
    });
    dispatch_async(queue3, ^{
        NSLog(@"%@:queue3", [NSThread currentThread]);
    });
    dispatch_async(queue4, ^{
        NSLog(@"%@:queue4", [NSThread currentThread]);
    });

这次是使用dispatch_set_target_queue函数指定目标为一个Serial Dispatch Queue,输出结果:

2015-06-19 07:16:11.244 GCD_Study[23239:1303] {name = (null), num = 2}:queue0
2015-06-19 07:16:11.246 GCD_Study[23239:1303] {name = (null), num = 2}:queue1
2015-06-19 07:16:11.247 GCD_Study[23239:1303] {name = (null), num = 2}:queue2
2015-06-19 07:16:11.248 GCD_Study[23239:1303] {name = (null), num = 2}:queue3
2015-06-19 07:16:11.250 GCD_Study[23239:1303] {name = (null), num = 2}:queue4

原本并行执行的多个Serial Dispatch Queue变成了串行执行。在必须将不可并行执行的处理追加到多个Serial Dispatch Queue中时,如果用dispatch_set_target_queue函数将目标指定为某一个Serial Dispatch Queue,即可防止处理并行执行。

想象这样一个场景:我想在几秒后执行某一个操作。这样的场景就需要用到dispatch_after函数了。下面的代码是在2秒后输出一个字符串:

- (void)dispatchAfter {
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 2ull * NSEC_PER_SEC);
    dispatch_queue_t queue = dispatch_get_main_queue();
    NSLog(@"Now");
    dispatch_after(time, queue, ^{
        NSLog(@"after 2sec");
    });
}

输出结果:

2015-06-19 07:46:20.182 GCD_Study[23269:607] Now
2015-06-19 07:46:22.183 GCD_Study[23269:607] after 2sec

虽然有误差,但大概也是2秒后了。因为dispatch_after函数并不是在指定的时间后执行处理,而是在指定的时间追加处理到Dispatch Queue。上面那段代码意思是在2秒后将执行任务的Block用dispatch_async追加到Main Dispatch Queue中。

下面说一下dispatch_after函数的三个参数。第一个参数是指定时间用的dispatch_time_t类型的值,该值用dispatch_time函数或者dispatch_walltime函数获得。dispatch_time函数获取的是从第一个参数指定的时间开始,到第二个参数指定的毫微秒单位时间后的时间。上面的代码中第一个参数用的DISPATCH_TIME_NOW,表示从现在开始,第二个参数是2ull*NSEC_PER_SEC,表示延迟2秒,合起来就是从现在开始2秒后将Block追加到Main Dispatch Queue中。

数值和NSEC_PER_SEC的乘积得到单位为毫微秒的数值。有以下取值

#define NSEC_PER_USEC    1000ull        /* nanoseconds per microsecond */
#define USEC_PER_SEC    1000000ull    /* microseconds per second */
#define NSEC_PER_SEC    1000000000ull    /* nanoseconds per second */
#define NSEC_PER_MSEC    1000000ull    /* nanoseconds per millisecond */

NSEC_PER_USEC:1000纳秒/1微秒

USEC_PER_SEC  :1000000微秒/1秒

NSEC_PER_SEC  :1000000000纳秒/1秒

NSEC_PER_MSEC:1000000纳秒/1毫秒

ull是C语言中得数值字面量,是显示表明类型时使用的字符串,表示unsigned long long。

时间: 2024-11-10 04:08:07

GCD多线程的使用(四)的相关文章

iOS多线程编程(四)------ GCD(Grand Central Dispatch)

一.简介 是基于C语言开发的一套多线程开发机制,也是目前苹果官方推荐的多线程开发方法,用起来也最简单,只是它基于C语言开发,并不像NSOperation是面向对象的开发,而是完全面向过程的.如果使用GCD,完全由系统管理线程,我们不需要编写线程代码.只需定义想要执行的任务,然后添加到适当的调度队列(dispatch_queue).GCD会负责创建线程和调度你的任务,系统会直接提供线程管理. 二.任务和队列 GCD中有两个核心概念 (1)任务:执行什么操作 (2)队列:用来存放任务 GCD的使用就

iOS开发中的gcd多线程tips

iOS开发中的gcd多线程tips 我们经常用到的: dispatch_async(dispatch_get_global_queue(0, 0), ^{ // 处理耗时操作的代码块 //通知主线程刷新 dispatch_async(dispatch_get_main_queue(), ^{ //回调或者说是通知主线程刷新 }); }); 其中main_queue是系统默认的串行队列,global_queue是系统默认的并行队列. 什么是串行队列(Serial)? 创建任意个数的串行队列,每个队

Java多线程基础(四)Java传统线程同步通信技术

Java多线程基础(四)Java传统线程同步通信技术 编写代码实现以下功能 子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,接着再回到主线程又循环100次,如此循环50次. 分析 1)子线程循环10次与主线程循环100次必须是互斥的执行,不能出现交叉,下面代码中通过synchronized关键字实现此要求: 2)子线程与主线程必须交替出现,可以通过线程同步通信技术实现,下面代码中通过bShouldSub变量实现此要求: 其他需要注意的地方 1)其中business变量必须声

HDU 4910 HDOJ Problem about GCD BestCoder #3 第四题

首先 m = 1 时 ans = 0对于 m > 1 的 情况 由于 1 到 m-1 中所有和m互质的数字,在 对m的乘法取模 运算上形成了群 ai = ( 1<=a<m && gcd(a,m) == 1 ) 所以 对于 a 必然存在b = a^(-1) = inv(a) 使得 a * b = 1 (mod m) 这里存在两种情况 a != b 那么最后的连乘式中a b均出现一次,相乘得1 a == b 那么最后的连乘式中只出现一个a 实际上所有 a = inv(a) 的

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

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

进程同步概念简介 多线程上篇(四)

进程同步概念 临界资源 一旦有对资源的共享,就必然涉及竞争限制 比如尽管有两个人去水井打水,但是水井却只有一个:合理安排的话刚好错开,但是如果安排不合理,那就会出现冲突,出现冲突怎么办?总有一个先来后到,等下就好了. 这个水井就是一个临界资源 临界资源用来表示一种公共资源或者说是共享数据,可以被多个线程使用. 但是每一次,只能有一个线程使用它,一旦临界资源被占用,其他线程要想使用这个资源,就必须等待. 当多进程访问临界资源时,比如打印机 假设A进程和B进程轮流获得CPU时间片执行,A打印数学,B

多线程编程(四)GCD

前文中,我们介绍了多线程的基本概念和多线程编程实现的两种方式,本文,我们介绍一下最后一种多线程编程工具,也是最重要的一种:GCD. 1. GCD简介 1.1 什么是GCD GCD全称是Grand Central Dispatch,可译为"牛逼的中枢调度器" ,纯C语言,提供了非常多强大的函数.GCD为我们编写代码提供了非常绝佳的体验.它是苹果公司为在多核心设备上实现多线程充分利用多核优势提供的解决方案,在很多技术中,如 RunLoop GCD都扮演了重要的角色.GCD全称Grand C

ios多线程操作(四)—— GCD核心概念

GCD全称Grand Central Dispatch,可译为"大派发中枢调度器",以纯C语言写成,提供了许多非常强大的函数.GCD是苹果公司为多核的并行运算提出的解决方案,它可以自动利用更多的CPU内核来参与运算,会自动管理线程的生命周(创建线程.调度任务.销毁线程),而程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码! GCD中有两个核心概念,一是任务,二是队列. 任务:要执行什么样的操作.任务都是预先以Block封装好准备要执行的一段代码. 队列:用来存放任务,

GCD - 多线程

什么是 GCD GCD 是 libdispatch 的市场名称,而 libdispatch 作为 Apple 的一个库,为并发代码在多核硬件(跑 iOS 或 OS X )上执行提供有力支持.它具有以下优点: 1.GCD 能通过推迟昂贵计算任务,并在后台运行它们改善应用的响应性能. 2.GCD 提供一个易于使用的并发模型而不仅仅只是锁和线程,以帮助我们避开并发陷阱. 3.GCD 具有在常见模式(例如单例),用更高性能的原语优化你的代码. GCD 术语 Serial vs. Concurrent 串