『ios』关于单例 dispatch_once原理的学习

2021-03-08  本文已影响0人  butterflyer

dispatch_once我们平时经常用吧,特别是创建单例的时候,但是可能我们平时只是在于用它,并不知道他是如何实现的。
我也在思考这个问题。

+(instancetype)shareInstance{
    static ServiceApp *service = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        service = [[ServiceApp alloc]init];
    });
    return service;
}

单例是如何只执行一次的呢?
带着这个问题,我们往下看。
这个函数的基本内部构成,我们主要看这个函数dispatch_once_f。

#ifdef __BLOCKS__
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
DISPATCH_EXPORT DISPATCH_NONNULL_ALL DISPATCH_NOTHROW
void
dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);

//注意这个内联函数
DISPATCH_INLINE DISPATCH_ALWAYS_INLINE DISPATCH_NONNULL_ALL DISPATCH_NOTHROW
void
_dispatch_once(dispatch_once_t *predicate, dispatch_block_t block)
{
    if (DISPATCH_EXPECT(*predicate, ~0l) != ~0l) {
        dispatch_once(predicate, block);
    }
}
#undef dispatch_once
#define dispatch_once _dispatch_once
#endif
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
DISPATCH_EXPORT DISPATCH_NONNULL1 DISPATCH_NONNULL3 DISPATCH_NOTHROW
void
dispatch_once_f(dispatch_once_t *predicate, void *context,
        dispatch_function_t function);

DISPATCH_INLINE DISPATCH_ALWAYS_INLINE DISPATCH_NONNULL1 DISPATCH_NONNULL3
DISPATCH_NOTHROW
void
_dispatch_once_f(dispatch_once_t *predicate, void *context,
        dispatch_function_t function)
{
    if (DISPATCH_EXPECT(*predicate, ~0l) != ~0l) {
        dispatch_once_f(predicate, context, function);
    }
}
#undef dispatch_once_f
#define dispatch_once_f _dispatch_once_f

__END_DECLS

#endif

下面我们来看dispatch_once_f。


dispatch_once_f(dispatch_once_t *val, void *ctxt, dispatch_function_t func)
{
//结构体
dispatch_once_gate_t l = (dispatch_once_gate_t)val;
 //这里我们放到后面去看,请记住DLOCK_ONCE_DONE这个东西
#if !DISPATCH_ONCE_INLINE_FASTPATH || DISPATCH_ONCE_USE_QUIESCENT_COUNTER
    uintptr_t v = os_atomic_load(&l->dgo_once, acquire);
    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);

通过查阅资料,dispatch_once_gate_t是一个结构体。
我们来看这个函数。

if (_dispatch_once_gate_tryenter(l)) {
        return _dispatch_once_callout(l, ctxt, func);
    }

_dispatch_once_gate_tryenter(dispatch_once_gate_t l)
{
    // os 对象是否存储过
    // unlock
    return os_atomic_cmpxchg(&l->dgo_once, DLOCK_ONCE_UNLOCKED,
            (uintptr_t)_dispatch_lock_value_for_self(), relaxed);
}

dispatch_once_callout是执行dispatch_once block里的函数。

_dispatch_once_callout(dispatch_once_gate_t l, void *ctxt,
        dispatch_function_t func)
{
    _dispatch_client_callout(ctxt, func);
    _dispatch_once_gate_broadcast(l);
}

执行完_dispatch_client_callout这个函数,就执行下面的广播函数_dispatch_once_gate_broadcast(l) 。


_dispatch_once_gate_broadcast(dispatch_once_gate_t l)
{
    dispatch_lock value_self = _dispatch_lock_value_for_self();
    uintptr_t v;
#if DISPATCH_ONCE_USE_QUIESCENT_COUNTER
    v = _dispatch_once_mark_quiescing(l);
#else
    v = _dispatch_once_mark_done(l);
#endif
    if (likely((dispatch_lock)v == value_self)) return;
    _dispatch_gate_broadcast_slow(&l->dgo_gate, (dispatch_lock)v);
}

我们主要看_dispatch_once_mark_quiescing和_dispatch_once_mark_done这两个地方。


_dispatch_once_mark_quiescing(dispatch_once_gate_t dgo)
{
    return os_atomic_xchg(&dgo->dgo_once, _dispatch_once_generation(), release);
}

_dispatch_once_mark_quiescing标记着正在创建。


_dispatch_once_mark_done(dispatch_once_gate_t dgo)
{
    return os_atomic_xchg(&dgo->dgo_once, DLOCK_ONCE_DONE, release);
}

_dispatch_once_mark_done标识结束,并标记为DLOCK_ONCE_DONE。


_dispatch_once_mark_done(dispatch_once_gate_t dgo)
{
    return os_atomic_xchg(&dgo->dgo_once, DLOCK_ONCE_DONE, release);
}

在这里我们可以回头看,最开始dispatch_once_f中的代码。

uintptr_t v = os_atomic_load(&l->dgo_once, acquire);
    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);
    }

相信看到DLOCK_ONCE_DONE,就应该懂了,是什么。如果检测到已经执行过,就直接返回。
如果是正在创建,就执行_dispatch_once_mark_done_if_quiesced,并标记为DLOCK_ONCE_DONE。


_dispatch_once_mark_done_if_quiesced(dispatch_once_gate_t dgo, uintptr_t gen)
{
    if (_dispatch_once_generation() - gen >= DISPATCH_ONCE_GEN_SAFE_DELTA) {
        /*
         * See explanation above, when the quiescing counter approach is taken
         * then this store needs only to be relaxed as it is used as a witness
         * that the required barriers have happened.
         */
        os_atomic_store(&dgo->dgo_once, DLOCK_ONCE_DONE, relaxed);
    }
}

dispatch_once的原理大概就是这样了。为什么只执行一次。
主要在DLOCK_ONCE_DONE这个标记。

上一篇下一篇

猜你喜欢

热点阅读