iOS - GCD单例、栅栏、信号量

2021-04-15  本文已影响0人  Gumball_a45f

1.单例

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    NSLog(@"单例应用");
});

平常我们会用到上面的代码来创建单例。

单例的特点是单例只执行一次

那他底层是如何处理的,让他只执行一次?且他的block哪时候调用的?

带着这个问题,进入单例的底层来看看。

void
dispatch_once(dispatch_once_t *val, dispatch_block_t block)
{
    dispatch_once_f(val, block, _dispatch_Block_invoke(block));
}

内部处理

DISPATCH_NOINLINE
void
dispatch_once_f(dispatch_once_t *val, void *ctxt, dispatch_function_t func)
{
    dispatch_once_gate_t l = (dispatch_once_gate_t)val;

#if !DISPATCH_ONCE_INLINE_FASTPATH || DISPATCH_ONCE_USE_QUIESCENT_COUNTER
    uintptr_t v = os_atomic_load(&l->dgo_once, acquire);//load
    if (likely(v == DLOCK_ONCE_DONE)) {//已经执行过了,直接返回
        return;
    }
#if DISPATCH_ONCE_USE_QUIESCENT_COUNTER
    if (likely(DISPATCH_ONCE_IS_GEN(v))) {
        return _dispatch_once_mark_done_if_quiesced(l, v);
    }
#endif
#endif
    if (_dispatch_once_gate_tryenter(l)) {//尝试进入
        return _dispatch_once_callout(l, ctxt, func);
    }
    return _dispatch_once_wait(l);//无限次等待
}

单例总结:

2.栅栏函数

栅栏函数的主要作用:控制队列的执行顺序(但只能控制同一并发队列的顺序)

栅栏函数主要有:

通俗的讲就是栅栏在两个执行语句中间,隔开

在使用栅栏函数时.使用自定义队列才有意义,如果用的是串行队列或者系统提供的全局并发队列,这个栅栏函数的作用等同于一个同步函数的作用,没有任何意义

3.信号量

信号量的作用一般是用来使任务同步执行,类似于互斥锁,用户可以根据需要控制GCD最大并发数,一般是这样使用的

//信号量
dispatch_semaphore_t sem = dispatch_semaphore_create(1);

dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
dispatch_semaphore_signal(sem);

信号量:其实是可以在不同队列中使用同一个信号量的,
也可以让异步并行队列按顺序执行。

4.调度组

调度组的最直接作用是控制任务执行顺序

常规使用方法:

dispatch_group_create 创建组 
dispatch_group_async 进组任务 
dispatch_group_notify 进组任务执行完毕通知 dispatch_group_wait 进组任务执行等待时间

//进组和出组一般是成对使用的
dispatch_group_enter 进组 
dispatch_group_leave 出组

dispatch_group_enter 进组 ,dispatch_group_leave 出组是成对出现的,否则dispatch_group_notify 不调用,

dispatch_group_async 等同于enter - leave,其底层的实现就是enter-leave

dispatch_group_async :

但如果group的block内部有其他异步并行队列就不会等待了,会直接执行dispatch_group_notify

而dispatch_group_enter、和dispatch_group_leave则不会有这个问题

上一篇下一篇

猜你喜欢

热点阅读