简介


  • GCD(Grand Center Dispatch)是Apple为多核的并行运算提出的解决方案,纯C语言
  • 更加适配多核处理器,且自动管理线程的生命周期,使用起来较为方便
  • GCD通过任务和队列实现多线程功能
    • 任务:描述所要执行的操作
    • 队列:用来存放所要执行的任务,队列中的任务遵循FIFO(First In First Out)原则

GCD的任务函数(是否开启新的线程)


  • 同步

    • 不具备开启新的线程的能力
    • 同步执行任务的函数
      • void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block),Block类型

        • queue:任务队列
        • block(代码块):所执行的任务
      • void dispatch_sync_f(dispatch_queue_t queue, void *context, dispatch_function_t work),函数类型(每个Block类型都对应一个函数类型)
        • queue:任务队列
        • context:传递给任务函数的参数
        • work(函数):所执行的任务
    • 同步执行任务的其他函数(barrier),在前面的任务执行完毕它才执行,它后边的任务等它执行完毕才执行
      • void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block),block类型

        • queue:任务队列,仅当该参数为并发队列时,该函数才有意义
      • dispatch_barrier_sync_f(dispatch_queue_t queue, void *context, dispatch_function_t work),函数类型
  • 异步

    • 具备开启新的线程的能力(需要将任务添加到并发队列中)
    • 异步执行任务的函数(参数意义与同步函数相同)
      • void dispatch_async(dispatch_queue_t queue, dispatch_block_t block)
      • void dispatch_async_f(dispatch_queue_t queue, void *context, dispatch_function_t work)
    • 异步执行任务的其他函数(barrier),在前面的任务执行完毕它才执行,它后边的任务等它执行完毕才执行(参数意义与同步函数相同)
      • void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block)
      • void dispatch_barrier_async_f(dispatch_queue_t queue, void *context, dispatch_function_t work)

GCD的队列(任务的执行方式)


  • 并发队列

    • 开启多个线程,使队列中的多个任务并发执行(需要异步执行函数的配合)
  • 串行队列
    • 队列中的任务一个接一个顺序地执行
  • 队列的种类
    • 串行队列

      • dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)

        • label:通常为0
        • attr:队列类型,DISPATCH_QUEUE_SERIAL
    • 并发队列
      • dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr)

        • label:通常为0
        • attr:队列类型 DISPATCH_QUEUE_CONCURRENT
    • 主队列(串行,只能在主线程中运行)
      • dispatch_queue_t dispatch_get_main_queue(void),获取主队列
    • 全局队列(并发)
      • dispatch_queue_t dispatch_get_global_queue(long identifier, unsigned long flags)

任务与队列的组合


  • 同步函数

    • 同步函数主队列

      /**
      - 运行在主线程主队列(未开启新的线程),主线程被卡死
      - 原因:任务代码等待着当前函数执行完毕才能执行(当前函数正在执行且未执行完毕);
      当前函数等待着任务代码 执行完毕才能执行(当前任务正在执行且未执行完毕);
      相互等待,出现死锁
      */ //获取主队列
      dispatch_queue_t queue = dispatch_get_main_queue();
      //添加任务到队列
      dispatch_sync(queue, ^{
      //任务1代码
      });
      dispatch_sync(queue, ^{
      //任务2代码
      });
    • 同步函数串行队列

      /**
      - 运行在主线程串行非主队列(未开启新的线程),任务串行执行
      */ //创建串行队列
      dispatch_queue_t queue = dispatch_queue_create("com.23565@qq", DISPATCH_QUEUE_SERIAL);
      //添加任务到队列
      dispatch_sync(queue, ^{
      //任务1代码
      });
      dispatch_sync(queue, ^{
      //任务2代码
      });
    • 同步函数并发队列

      /**
      - 运行在非主线程并发队列(未开启新的线程),任务串行执行
      */ //获取全局队列(并发)
      dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
      //将任务加至队列
      dispatch_sync(queue, ^{
      //任务1代码
      });
      dispatch_sync(queue, ^{
      //任务2代码
      });
  • 异步函数
    • 异步函数主队列

      /**
      - 运行在主线程主队列(未开启新的线程),任务串行执行
      */ // 获得主队列
      dispatch_queue_t queue = dispatch_get_main_queue();
      // 将任务加入队列
      dispatch_async(queue, ^{
      //任务1代码
      });
      dispatch_async(queue, ^{
      //任务2代码
      });
    • 异步函数串行队列

      /**
      - 运行在主函数串行非主队列(未开启新的线程),任务串行执行
      */ //创建串行队列
      dispatch_queue_t queue = dispatch_queue_create("com.23565@qq", DISPATCH_QUEUE_SERIAL);
      //将任务加至队列
      dispatch_async(queue, ^{
      //任务1代码
      })
      dispatch_async(queue, ^{
      //任务2代码
      })
    • 异步函数并发队列

      /**
      - 运行在非主线程并发队列(开启新的线程),任务并发执行
      - 系统根据任务创建线程(无法确定任务执行在哪个线程)
      */ //获得全局并发队列
      dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
      //将任务加入队列
      dispatch_async(queue, ^{
      //任务1代码
      });
      dispatch_async(queue, ^{
      //任务2代码
      });

线程之间的通信


  • 从主线程到子线程

    • 注意

      • 只有异步函数与并发队列的组合,才会开启新的线程,使任务并发执行
      • 通常使用异步函数将任务添加到并发队列中,来实现从主线程到子线程的通信
    • 实现代码

      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      //需要在子线程中执行的任务代码
      })
  • 从子线程到主线程
    • 注意

      • 主队列中的任务只能在主线程中执行
      • 通常使用异步/同步函数将任务添加到主队列中,来实现从子线程到主线程的通信
    • 实现代码

      dispatch_async(dispatch_get_main_queue(), ^{
      //需要在主线程中执行的代码
      })

GCD的其他任务


  • 单次执行(通常用在单例模式的设计中)

    //定义一个标记
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    //此处的代码只会被执行一次
    });
  • 延迟执行

    /**
    - 方法一(GCD)
    */
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    //此处的代码将延迟执行
    }); /**
    - 方法二(performSelector)
    */
    [self performSelector:@selector(run) withObject:self afterDelay:2.0]; /**
    - 方法三(NSTimer)
    */
    [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO]
  • 快速迭代

    void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t))
    /**
    iterations:迭代执行的次数
    queue:任务队列
    block:迭代执行的代码
    size_t:用来定义当前迭代到第几次,需要自己添加,如在size_t后添加index索引,记录当前的迭代次数
    */
  • Barrier

    /**
    - Barrier中的任务,只能在它前面的任务执行完毕才能执行
    Barrier后的任务,只能等到它执行完毕才能执行
    - 要将队列添加到自己创建的并发队列中,否其功能等同于函数
    void dispatch_async(dispatch_queue_t queue, dispatch_block_t block)
    */
    //创建队列(通常是自己创建的并发队列)
    dispatch_queue_t queue = dispatch_queue_create("123", DISPATCH_QUEUE_CONCURRENT);
    //将任务添加到队列
    dispatch_async(queue, ^{
    //在Barrier前执行的任务代码
    });
    dispatch_barrier_async(queue, ^{
    //Barrier中的任务代码
    });
    dispatch_async(queue, ^{
    //在Barrier后执行的任务代码
    });
  • 队列组

    //获取全局并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //创建队列组
    dispatch_group_t group = dispatch_group_create();
    //添加任务到队列组
    dispatch_group_async(group, queue, ^{
    //任务1代码
    });
    dispatch_group_async(group, queue, ^{
    //任务2代码
    });
    dispatch_group_notify(group, queue, ^{
    //任务3代码
    /**
    group组中的所有任务执行完毕在执行
    若group为空,则立即执行
    */
    });

##GCD定时器 ---
- 实现原理
- 创建一个DISPATCH_SOURCE_TYPE_TIMER类型的dispatch source,并添加到dispatch queue,通过dispatch source来响应事件
- 通过函数void dispatch_source_set_timer(dispatch_source_t source, dispatch_time_t start, uint64_t interval, uint64_t leeway),来设置dispatch source的执行事件 - 实现代码 ```
//获得队列
dispatch_queue_t queue = dispatch_get_main_queue();
//创建一个定时器
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); //设置定时器的各种属性(起止时间)
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(8.0 * NSEC_PER_SEC));
uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);
//设置
dispatch_source_set_timer(self.timer, start, interval, 0); //设置回调
dispatch_source_set_event_handler(self.timer, ^{
//定时器被触发时所要执行的代码
}); //开启定时器
dispatch_resume(self.timer);
//取消定时器
dispatch_cancel(self.timer);
```

iOS多线程-02-GCD的更多相关文章

  1. [iOS]多线程和GCD

    新博客wossoneri.com 进程和线程 进程 是指在系统中正在运行的一个应用程序. 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内. 比如同时打开QQ.Xcode,系统就会分别 ...

  2. iOS多线程 NSThread/GCD/NSOperationQueue

    无论是GCD,NSOperationQueue或是NSThread, 都没有线程安全 在需要同步的时候需要使用NSLock或者它的子类进行加锁同步 "] UTF8String], DISPA ...

  3. iOS 多线程 之 GCD(大中枢派发)(一)

    导语: 本文个人原创,转载请注明出处(http://www.cnblogs.com/pretty-guy/p/8126981.html) 在iOS开发中多线程操作通常是一下3种,本文着重介绍Dispa ...

  4. IOS多线程(GCD)

    简介 Grand Central Dispatch 简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统.这建立在任务并行执行的线程池模式的基础上的.它首次 ...

  5. ios 多线程小结----- GCD篇

    //3 GCD(充分利用设备的多盒)-------------屏蔽了线程,只能看见任务 队列步骤两步,定制任务,将任务添加到队列.GCD将添加的任务,放到线程中去执行,自动执行,自动释放原则:先进先出 ...

  6. IOS 多线程 NSOperation GCD

    1.NSInvocationOperation NSInvocationOperation * op; NSOperationQueue * que = [[NSOperationQueuealloc ...

  7. iOS 多线程之 GCD 的基本使用

    什么是GCD 全称Grand Central Dispatch 中暑调度器 纯C语言 提供了很多强大的函数 GCD 的优势 GCD是苹果公司为多核的并行运算提出的解决方案 GCD会自动利用更多的CPU ...

  8. iOS 多线程 之 GCD(大中枢派发)(二)

    本文接着上一篇讲.主要讲:dispatch_source. dispatch_source主要用户监听事件,可以监听如下事件 DISPATCH_SOURCE_TYPE_DATA_ADD DISPATC ...

  9. iOS 多线程:『GCD』详尽总结

    本文用来介绍 iOS 多线程中 GCD 的相关知识以及使用方法.这大概是史上最详细.清晰的关于 GCD 的详细讲解+总结的文章了.通过本文,您将了解到: 1. GCD 简介 2. GCD 任务和队列 ...

  10. iOS 多线程 GCD part3:API

    https://www.jianshu.com/p/072111f5889d 2017.03.05 22:54* 字数 1667 阅读 88评论 0喜欢 1 0. 预备知识 GCD对时间的描述有些新奇 ...

随机推荐

  1. Android之Handler源码深入分析

    闲着没事,就来看看源码,看看源码的各种原理,会用只是简单的,知道为什么才是最牛逼的. Handler源码分析那,从使用的步骤来边用边分析: 1.创建一个Handler对象:new Handler(ge ...

  2. I'm back for Machine Learning

    Hi, Long time no see. Briefly, I plan to step into this new area, data analysis. In the past few yea ...

  3. JS微信分享不好写?来封装一下

    微信开发这块,作为开发工程师来说,一般是避免不了的,也好像发现一些朋友写微信分享都是在每个页面一大把一大把的代码. 代码冗余,即便是复制过来再改也很麻烦. 之前自己封装了一下js,今天来分享一下,希望 ...

  4. 《构建之法》阅读有疑 与 个人Week1作业

    <构建之法>阅读有疑 在用将近五节课的时间将邹欣老师的书<构建之法——现代软件工程>第二版大致看完.虽然全书是以轻松的口吻与”移山公司”员工的一些趣味谈话来传输一些理念和思想的 ...

  5. Scrum团队成立

    1.团队名称:瘦子不吃肥肉 目标:学习更多,了解更多! 口号:加油 团队照: 2.角色分配: 产品负责人:卓嘉炜        http://www.cnblogs.com/luoliuxi/ Scr ...

  6. Scrum 项目1.0 2.0 3.0 4.0 5.0 6.0 7.0

    1.确定选题. 应用NABCD模型,分析你们初步选定的项目,充分说明你们选题的理由. 录制为演说视频,上传到视频网站,并把链接发到团队博客上. 截止日期:2016.5.6日晚10点 阅读教材第8章,8 ...

  7. 数论 - 算数基本定理的运用 --- nefu 118 : n!后面有多少个0

     题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemshow.php Mean: 略. analyse: 刚开始想了半天都没想出来,数据这么大,难道是有什么 ...

  8. AEAI DP开发平台升级说明

    本次发版的AEAI DP_v3.5.0版本为AEAI DP _v3.4.0版本的升级版本,该产品现已开源并上传至开源社区http://www.oschina.net/p/aeaidp. 1 升级说明 ...

  9. 字典树(Trie树)实现与应用

    一.概述 1.基本概念 字典树,又称为单词查找树,Tire数,是一种树形结构,它是一种哈希树的变种. 2.基本性质 根节点不包含字符,除根节点外的每一个子节点都包含一个字符 从根节点到某一节点.路径上 ...

  10. SQL 日期转换(阳历转阴历)

    --步骤:创建日期表,放初始放初始化资料 --因为农历的日,是由天文学家推算出来,到现在只有到年,以后的有了还可以加入! if object_id('SolarData') is not nulldr ...