GCD系列函数

129 阅读3分钟

dispatch_once 仅执行一次 一般用于单例实现

实现方式一

#import "FaceManager.h"
static FaceManager *faceManager = nil;
@implementation FaceManager
+(instancetype)sharedInstance
{
    static  dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        faceManager = [[FaceManager alloc] init];
    });

    return faceManager;
}

注意:

//防止 alloc  init  new 引起的错误
+(instancetype)allocWithZone:(struct _NSZone *)zone
{
    return [FaceManager sharedInstance];
}

//防止NSCopying  引起的错误

-(id)copyWithZone:(NSZone *)zone
{
    return [FaceManager sharedInstance];
}

//防止NSMutableCopying 引起的错误
-(id)mutableCopyWithZone:(NSZone *)zone  {
    return [FaceManager sharedInstance];
}

底层实现原理:

image.png

val:标记任务的执行状态 dispatch_once_f:执行的任务

image.png

底层有一个监测任务是否执行过的标记

  • 已经执行过就直接return
  • 未执行过,则开始执行,执行完就更新标记已执行完通知更新标记状态
  • 正在执行中,则等待,通过循环拿取执行状态,通过状态来判断是否执行任务

GCD栅栏函数

自定义并发 栅栏函数

  • 栅栏前面的队列里的任务 > 栅栏里的任务 > 栅栏后面队列里的任务

image.png

打印结果: 5 23 4 6

image.png

全局并发 栅栏函数(无效),

  • 栅栏 拦不住

全局并发异步 image.png 全局并发 同步

image.png

主队列是可以拦住的,大家自行验证

为什么全局并发队列拦不住呢?

  • 1、全局并发队列处任务的函数没有判断栅栏函数相关的代码
  • 2、如果全局并发队列被栅栏住,将会影响操作系统函数的一些调用,显然不合适

栅栏函数能够栅住任务的原因:通过队列的一个状态值控制任务的执行顺序

GCD dispatch_group 调度组的作用:通过组的一个状态值来控制任务的执行顺序 与栅栏函数不同的是 组里的任务可以按顺序,而栅栏是控制 栅栏前的任务和栅栏后的任务,,而前面和后面的多个任务是无法确定顺序的

image.png

反观上面栅栏函数 栅栏前面多个任务并发是没有顺序的

  • 1、调度组 dispatch_group_async == dispatch_group_enter + dispatch_group_leave
  • 2、dispatch_group_notify作为调度组的最终入口会判断ds_status的值也就是组中任务的状态,所有任务完成之后方可进入notify函数 3、dispatch_group_enter 调度组里面值 +1 和 dispatch_group_leave 调度组里面值 -1 且必须成对出现

image.png

GCD 信号量

  • 1、创建信号量 create 创建可控制的线程的个数
  • dispatch_semaphore_t semphor = dispatch_semaphore_create(2);
  • 其中2表示控制的线程的个数
  • 2、等待信号量 对信号量的值—1操作 值为0 阻塞线程 一直等待直到值 >=1 才继续往下走
  • dispatch_semaphore_wait(semphor, DISPATCH_TIME_FOREVER);
  • 3、signal 发送信号量 -- 基于信号量的值+1
  • dispatch_semaphore_signal(semphor);

作用:

  • 控制并发线程数量 信号量的值为0时,按照顺序执行 结果:1 2 3 4

image.png

信号量的值为1时,按照顺序执行 结果:顺序不确定

image.png

总结:

  • 当初始化的信号量的值 为0 时能控制执行的顺序,
  • 当初始化的信号量的值 >0 时能控制并发的线程的执行顺序
  • 注意:wait和signal必须成对出现,否则会导致崩溃 举例:
dispatch_semaphore_t semphor = dispatch_semaphore_create(1);
dispatch_semaphore_wait(semphor, DISPATCH_TIME_FOREVER);

那么为什么会崩溃呢?

  • 报错到:_dispatch_semaphore_dispose,该函数是释放信号量的函数

image.png

  • 结论 :signal 和wait 函数必须成对出现 如果初始值为0,则会一直等待 GCD dispatch_source实现
  • 1、创建队列,
  • 2、创建源,确定源的类型
  • 3、启动 和暂停 设置倒计时

image.png