完结篇,原帖地址:http://www.dreamingwish.com/dream-2012/gcd-four-the-the-odds-and-ends.html

Dispatch Queue挂起

dispatch queue可以被挂起和恢复。使用 dispatch_suspend函数来挂起,使用  dispatch_resume 函数来恢复。这两个函数的行为是如你所愿的。另外,这两个还是也可以用于dispatch source。

一个要注意的地方是,dispatch queue的挂起是block粒度的。换句话说,挂起一个queue并不会将当前正在执行的block挂起。它会允许当前执行的block执行完毕,然后后续的block不再会被执行,直至queue被恢复。

还有一个注意点:从man页上得来的:如果你挂起了一个queue或者source,那么销毁它之前,必须先对其进行恢复。

Dispatch Queue目标指定

所有的用户队列都有一个目标队列概念。从本质上讲,一个用户队列实际上是不执行任何任务的,但是它会将任务传递给它的目标队列来执行。通常,目标队列是默认优先级的全局队列。

用户队列的目标队列可以用函数 dispatch_set_target_queue来修改。我们可以将任意dispatch queue传递给这个函数,甚至可以是另一个用户队列,只要别构成循环就行。这个函数可以用来设定用户队列的优先级。比如我们可以将用户队列的目标队列设定为低优先级的全局队列,那么我们的用户队列中的任务都会以低优先级执行。高优先级也是一样道理。

有一个用途,是将用户队列的目标定为main queue。这会导致所有提交到该用户队列的block在主线程中执行。这样做来替代直接在主线程中执行代码的好处在于,我们的用户队列可以单独地被挂起和恢复,还可以被重定目标至一个全局队列,然后所有的block会变成在全局队列上执行(只要你确保你的代码离开主线程不会有问题)。

还有一个用途,是将一个用户队列的目标队列指定为另一个用户队列。这样做可以强制多个队列相互协调地串行执行,这样足以构建一组队列,通过挂起和暂停那个目标队列,我们可以挂起和暂停整个组。想象这样一个程序:它扫描一组目录并且加载目录中的内容。为了避免磁盘竞争,我们要确定在同一个物理磁盘上同时只有一个文件加载任务在执行。而希望可以同时从不同的物理磁盘上读取多个文件。要实现这个,我们要做的就是创建一个dispatch queue结构,该结构为磁盘结构的镜像。

首先,我们会扫描系统并找到各个磁盘,为每个磁盘创建一个用户队列。然后扫描文件系统,并为每个文件系统创建一个用户队列,将这些用户队列的目标队列指向合适的磁盘用户队列。最后,每个目录扫描器有自己的队列,其目标队列指向目录所在的文件系统的队列。目录扫描器枚举自己的目录并为每个文件向自己的队列提交一个block。由于整个系统的建立方式,就使得每个物理磁盘被串行访问,而多个物理磁盘被并行访问。除了队列初始化过程,我们根本不需要手动干预什么东西。

信号量

dispatch的信号量是像其他的信号量一样的,如果你熟悉其他多线程系统中的信号量,那么这一节的东西再好理解不过了。

信号量是一个整形值并且具有一个初始计数值,并且支持两个操作:信号通知和等待。当一个信号量被信号通知,其计数会被增加。当一个线程在一个信号量上等待时,线程会被阻塞(如果有必要的话),直至计数器大于零,然后线程会减少这个计数。

我们使用函数  dispatch_semaphore_create 来创建dispatch信号量,使用函数  dispatch_semaphore_signal 来信号通知,使用函数dispatch_semaphore_wait 来等待。这些函数的man页有两个很好的例子,展示了怎样使用信号量来同步任务和有限资源访问控制。

单次初始化

GCD还提供单词初始化支持,这个与pthread中的函数  pthread_once 很相似。GCD提供的方式的优点在于它使用block而非函数指针,这就允许更自然的代码方式:

这个特性的主要用途是惰性单例初始化或者其他的线程安全数据共享。典型的单例初始化技术看起来像这样(线程安全的):

  1. + (id)sharedWhatever
  2. {
  3. static Whatever *whatever = nil;
  4. @synchronized([Whatever class])
  5. {
  6. if(!whatever)
  7. whatever = [[Whatever alloc] init];
  8. }
  9. return whatever;
  10. }

这挺好的,但是代价比较昂贵;每次调用  +sharedWhatever 函数都会付出取锁的代价,即使这个锁只需要进行一次。确实有更风骚的方式来实现这个,使用类似双向锁或者是原子操作的东西,但是这样挺难弄而且容易出错。

使用GCD,我们可以这样重写上面的方法,使用函数 dispatch_once

  1. + (id)sharedWhatever
  2. {
  3. static dispatch_once_t pred;
  4. static Whatever *whatever = nil;
  5. dispatch_once(&pred, ^{
  6. whatever = [[Whatever alloc] init];
  7. });
  8. return whatever;
  9. }

这个稍微比 @synchronized方法简单些,并且GCD确保以更快的方式完成这些检测,它保证block中的代码在任何线程通过  dispatch_once 调用之前被执行,但它不会强制每次调用这个函数都让代码进行同步控制。实际上,如果你去看这个函数所在的头文件,你会发现目前它的实现其实是一个宏,进行了内联的初始化测试,这意味着通常情况下,你不用付出函数调用的负载代价,并且会有更少的同步控制负载。

结论

这一章,我们介绍了dispatch queue的挂起、恢复和目标重定,以及这些功能的一些用途。另外,我们还介绍了如何使用dispatch 信号量和单次初始化功能。到此,我已经完成了GCD如何运作以及如何使用的介绍。

GCD教程(四):完结的更多相关文章

  1. ASP.NET 5系列教程(七)完结篇-解读代码

    在本文中,我们将一起查看TodoController 类代码. [Route] 属性定义了Controller的URL 模板: [Route("api/[controller]") ...

  2. canvas基础简单易懂教程(完结,多图)

    目录 Canvas学习 一. Canvas概述 1.1 Hello world 1.2 Canvas的像素化 1.3 Canvas的动画思想 1.4 面向对象思维实现canvas动画 二.Canvas ...

  3. CRL快速开发框架系列教程四(删除数据)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  4. 手把手教从零开始在GitHub上使用Hexo搭建博客教程(四)-使用Travis自动部署Hexo(2)

    前言 前面一篇文章介绍了Travis自动部署Hexo的常规使用教程,也是个人比较推荐的方法. 前文最后也提到了在Windows系统中可能会有一些小问题,为了在Windows系统中也可以实现使用Trav ...

  5. C#微信公众号开发系列教程四(接收普通消息)

    微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...

  6. 无废话ExtJs 入门教程四[表单:FormPanel]

    无废话ExtJs 入门教程四[表单:FormPanel] extjs技术交流,欢迎加群(201926085) 继上一节内容,我们在窗体里加了个表单.如下所示代码区的第28行位置,items:form. ...

  7. TFS(Team Foundation Server)敏捷使用教程(四):工作项跟踪(1)

    工作项跟踪(1) 可跟踪性是软件过程的重要能力,TFS主要是以工作项来实现过程的可跟踪性.曾有人问:"你们实际项目里的工作项是怎么样的?能不能让我们看看?"我也一直很好奇别的公司T ...

  8. Android Studio系列教程四--Gradle基础

    Android Studio系列教程四--Gradle基础 2014 年 12 月 18 日 DevTools 本文为个人原创,欢迎转载,但请务必在明显位置注明出处!http://stormzhang ...

  9. Laravel教程 四:数据库和Eloquent

    Laravel教程 四:数据库和Eloquent 此文章为原创文章,未经同意,禁止转载. Eloquent Database 上一篇写了一些Laravel Blade的基本用法和给视图传递变量的几种方 ...

  10. NGUI系列教程四(自定义Atlas,Font)

    今天我们来看一下怎么自定义NGUIAtlas,制作属于自己风格的UI.第一部分:自定义 Atlas1 . 首先我们要准备一些图标素材,也就是我们的UI素材,将其导入到unity工程中.2. 全选我们需 ...

随机推荐

  1. USACO Section 1.1 Broken Necklace 解题报告

    题目 题目描述 有一串项链,它是由红蓝白三种颜色的珠子组成的,b代表蓝色,w代表白色,r代表红色,当它完整的时候是一个闭合的环形.现在它在某一个节点断裂了,之前的环形也随之变成了直线形.从两端开始收集 ...

  2. 试题公式解决方案--kindeditor集成jmeditor公式web编辑器

    最近在搞一套在线的考试系统,一直为即支持公式编辑又得支持各种附件上传.图片上传.视频音频上传.文字编辑 的web编辑器而犯愁.于是乎试着把 kindeditor和jmeditor集成一下,多了不说了直 ...

  3. document.createElement方法的使用

    我们在使用createElemen方法t创建一个元素节点的时候,似乎在IE下面怎么写都可以,但切换到FF等其它浏览器却总是会报错. 比如我们要创建一个input元素,那么在IE下,我们可以有多种写法: ...

  4. CentOS 6.4 x64 Cacti 监控安装配置

    Cacti 监控安装配置   环境:   安装Cacti 的服务器   Linux 6.4 x64   ip 10.8.8.11     一: 配置iptables , selinux     vi ...

  5. 隐藏Nginx版本号的安全性与方法

    搭建好nginx或者apache,为了安全起见我们都会隐藏他们的版本号,这边讲的是nginx的版本号,如果你也想隐藏apache的版本号,那请点前面的链接.请看nginx版本号信息隐藏文章. Ngin ...

  6. 在阿里云ECS(CentOS6.5)上安装jdk

    JDK安装 在安装前先确定服务器上没有安装过JDK 命令: java -version 结果: 查看所有java安装包 命令: yum -y list java* 结果: 选择安装所需要的JDK 命令 ...

  7. EQueue - 一个C#写的开源分布式消息队列的总体介绍(转)

    源: EQueue - 一个C#写的开源分布式消息队列的总体介绍 EQueue - 一个纯C#写的分布式消息队列介绍2 EQueue - 详细谈一下消息持久化以及消息堆积的设计

  8. Android线程之基本用法

    一: 在android中有两种实现线程thread的方法: 一种是,扩展java.lang.Thread类 另一种是,实现Runnable接口 二: Thread类代表线程类,它的两个最主要的方法是: ...

  9. ios 屏幕方向的设置

    ref: http://www.cnblogs.com/niit-soft-518/p/5611298.html 实际的项目需求.root是TabBarController,里面有4个navigati ...

  10. easyui 异步json tree跨域访问问题解决

    最近在用easyui中的异步tree时发现了跨域访问问题,我们都知道jquery ajax提供get请求的跨域访问.所以解决easyui tree跨域访问的问题便是将数据通过jquery ajax将数 ...