iOS底层-26:GCD底层源码探索(二)

单例dispatch_once

  • 搜索dispatch_once(dis
#ifdef __BLOCKS__
void
dispatch_once(dispatch_once_t *val, dispatch_block_t block)
{
    dispatch_once_f(val, block, _dispatch_Block_invoke(block));
}
#endif

传入两个参数,onceTokenblock,调用dispatch_once_f传入三个参数,由block生成的func

  • 搜索dispatch_once_f
DISPATCH_NOINLINE
void
dispatch_once_f(dispatch_once_t *val, void *ctxt, dispatch_function_t func)
{
    //将传入的静态变量保存到 l
    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);
    //当v == DLOCK_ONCE_DONE 直接return
    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)) {
        //callout func
        return _dispatch_once_callout(l, ctxt, func);
    }
      //避免多线程影响,其他线程进来在此函数等待
    return _dispatch_once_wait(l);
}
  • 查看_dispatch_once_callout
DISPATCH_NOINLINE
static void
_dispatch_once_callout(dispatch_once_gate_t l, void *ctxt,
        dispatch_function_t func)
{
    //调用block
    _dispatch_client_callout(ctxt, func);
    //设置l的值,标记block已经被执行过
    _dispatch_once_gate_broadcast(l);
}

dispatch_barrier 栅栏函数

dispatch_semaphore_t 信号量

我们从dispatch_semaphore_create开始

  • 搜索dispatch_semaphore_create
dispatch_semaphore_t
dispatch_semaphore_create(long value)
{
    dispatch_semaphore_t dsema;
    if (value < 0) {
        return DISPATCH_BAD_INPUT;
    }
    //开辟内存  
    dsema = _dispatch_object_alloc(DISPATCH_VTABLE(semaphore),
            sizeof(struct dispatch_semaphore_s));
    dsema->do_next = DISPATCH_OBJECT_LISTLESS;
    dsema->do_targetq = _dispatch_get_default_queue(false);
    dsema->dsema_value = value;
    _dispatch_sema4_init(&dsema->dsema_sema, _DSEMA4_POLICY_FIFO);
    dsema->dsema_orig = value;
    return dsema;
}

创建一个信号量,进行赋值然后return
接下来我们查看dispatch_semaphore_wait方法。

  • 搜索dispatch_semaphore_wait
long
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout)
{
    //os_atomic_sub(&(dsema)->dsema_value, (1), acquire)
    //_os_atomic_c11_op((&(dsema)->dsema_value), (1), acquire, sub, -)
    //让信号量的 value - 1
    long value = os_atomic_dec2o(dsema, dsema_value, acquire);
    if (likely(value >= 0)) {//大于等于0时,操作成功 正常返回
        return 0;
    }
    //特殊情况,进入长等待
    return _dispatch_semaphore_wait_slow(dsema, timeout);
}
  • 搜索_dispatch_semaphore_wait_slow
DISPATCH_NOINLINE
static long
_dispatch_semaphore_wait_slow(dispatch_semaphore_t dsema,
        dispatch_time_t timeout)
{
    long orig;

    _dispatch_sema4_create(&dsema->dsema_sema, _DSEMA4_POLICY_FIFO);
    switch (timeout) {
    default:
        if (!_dispatch_sema4_timedwait(&dsema->dsema_sema, timeout)) {
            break;
        }
        // Fall through and try to undo what the fast path did to
        // dsema->dsema_value
    case DISPATCH_TIME_NOW:
        orig = dsema->dsema_value;
        while (orig < 0) {
            if (os_atomic_cmpxchgvw2o(dsema, dsema_value, orig, orig + 1,
                    &orig, relaxed)) {
                return _DSEMA4_TIMEOUT();
            }
        }
        // Another thread called semaphore_signal().
        // Fall through and drain the wakeup.
    case DISPATCH_TIME_FOREVER:
        _dispatch_sema4_wait(&dsema->dsema_sema);
        break;
    }
    return 0;
}

接下来查看dispatch_semaphore_signal方法

  • 搜索dispatch_semaphore_signal
long
dispatch_semaphore_signal(dispatch_semaphore_t dsema)
{
    //与之对应 这里是把 value + 1
    long value = os_atomic_inc2o(dsema, dsema_value, release);
    if (likely(value > 0)) {//大于0 ,就表示正常情况;return 0表示处理成功
        return 0;
    }
    if (unlikely(value == LONG_MIN)) {
        DISPATCH_CLIENT_CRASH(value,
                "Unbalanced call to dispatch_semaphore_signal()");
    }
    //当value值不正常时,进入特殊情况 长等待
    return _dispatch_semaphore_signal_slow(dsema);
}

DISPATCH_NOINLINE
long
_dispatch_semaphore_signal_slow(dispatch_semaphore_t dsema)
{
    _dispatch_sema4_create(&dsema->dsema_sema, _DSEMA4_POLICY_FIFO);
    _dispatch_sema4_signal(&dsema->dsema_sema, 1);
    return 1;
}

dispatch_group 调度组

我们从dispatch_group_enter开始

  • 搜索dispatch_group_create(void)
dispatch_group_t
dispatch_group_create(void)
{
    return _dispatch_group_create_with_count(0);
}
  • 搜索_dispatch_group_create_with_count
DISPATCH_ALWAYS_INLINE
static inline dispatch_group_t
_dispatch_group_create_with_count(uint32_t n)
{    //开辟空间
    dispatch_group_t dg = _dispatch_object_alloc(DISPATCH_VTABLE(group),
            sizeof(struct dispatch_group_s));
    dg->do_next = DISPATCH_OBJECT_LISTLESS;
    dg->do_targetq = _dispatch_get_default_queue(false);
    if (n) {//创建时传入count 为 0
        os_atomic_store2o(dg, dg_bits,
                (uint32_t)-n * DISPATCH_GROUP_VALUE_INTERVAL, relaxed);
        os_atomic_store2o(dg, do_ref_cnt, 1, relaxed); // <rdar://22318411>
    }
    return dg;//直接返回
}

开辟一个空间,赋值do_nextdo_targetq然后返回。

  • 搜索dispatch_group_enter
void
dispatch_group_enter(dispatch_group_t dg)
{
    //这里和信号量一样,dg_bits - 1 初始为0 减1 变为 -1
    uint32_t old_bits = os_atomic_sub_orig2o(dg, dg_bits,
            DISPATCH_GROUP_VALUE_INTERVAL, acquire);
                                        //0x00000000fffffffcULL
    uint32_t old_value = old_bits & DISPATCH_GROUP_VALUE_MASK;
    if (unlikely(old_value == 0)) {
        _dispatch_retain(dg); //一
    }                                        //4
    if (unlikely(old_value == DISPATCH_GROUP_VALUE_MAX)) {
        DISPATCH_CLIENT_CRASH(old_bits,
                "Too many nested calls to dispatch_group_enter()");
    }//当old_value = 4 时会奔溃
}
  • 搜索dispatch_group_leave
void
dispatch_group_leave(dispatch_group_t dg)
{
    //与enter相反 这里进行+1操作
    uint64_t new_state, old_state = os_atomic_add_orig2o(dg, dg_state,
            DISPATCH_GROUP_VALUE_INTERVAL, release);
    uint32_t old_value = (uint32_t)(old_state & DISPATCH_GROUP_VALUE_MASK);
                                    //0x00000000fffffffcULL
    if (unlikely(old_value == DISPATCH_GROUP_VALUE_1)) {
        old_state += DISPATCH_GROUP_VALUE_INTERVAL;//old_state += 4;
        do {
            new_state = old_state;
            if ((old_state & DISPATCH_GROUP_VALUE_MASK) == 0) {
                new_state &= ~DISPATCH_GROUP_HAS_WAITERS;
                new_state &= ~DISPATCH_GROUP_HAS_NOTIFS;
            } else {
                new_state &= ~DISPATCH_GROUP_HAS_NOTIFS;
            }
            if (old_state == new_state) break;
        } while (unlikely(!os_atomic_cmpxchgv2o(dg, dg_state,
                old_state, new_state, &old_state, relaxed)));
        return _dispatch_group_wake(dg, old_state, true);
    }

    if (unlikely(old_value == 0)) {
        DISPATCH_CLIENT_CRASH((uintptr_t)old_value,
                "Unbalanced call to dispatch_group_leave()");
    }
}

dispatch_group_enter相反,这里状态码+1。

  • 搜索dispatch_group_notify
DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_group_notify(dispatch_group_t dg, dispatch_queue_t dq,
        dispatch_continuation_t dsn)
{
    uint64_t old_state, new_state;
    dispatch_continuation_t prev;

    dsn->dc_data = dq;
    _dispatch_retain(dq);//+1

    //从os 下层 拿到dg的状态码
    prev = os_mpsc_push_update_tail(os_mpsc(dg, dg_notify), dsn, do_next);
    if (os_mpsc_push_was_empty(prev)) _dispatch_retain(dg);
    os_mpsc_push_update_prev(os_mpsc(dg, dg_notify), prev, dsn, do_next);
    if (os_mpsc_push_was_empty(prev)) {
        os_atomic_rmw_loop2o(dg, dg_state, old_state, new_state, release, {
            new_state = old_state | DISPATCH_GROUP_HAS_NOTIFS;
            if ((uint32_t)old_state == 0) {
                os_atomic_rmw_loop_give_up({
                    //当state == 0 的时候,让group苏醒
                    return _dispatch_group_wake(dg, new_state, false);
                });
            }
        });
    }
}
  • 搜索_dispatch_group_wake
DISPATCH_NOINLINE
static void
_dispatch_group_wake(dispatch_group_t dg, uint64_t dg_state, bool needs_release)
{
    uint16_t refs = needs_release ? 1 : 0; // <rdar://problem/22318411>

    if (dg_state & DISPATCH_GROUP_HAS_NOTIFS) {
        dispatch_continuation_t dc, next_dc, tail;

        // Snapshot before anything is notified/woken <rdar://problem/8554546>
        dc = os_mpsc_capture_snapshot(os_mpsc(dg, dg_notify), &tail);
        do {
            dispatch_queue_t dsn_queue = (dispatch_queue_t)dc->dc_data;
            next_dc = os_mpsc_pop_snapshot_head(dc, tail, do_next);
            _dispatch_continuation_async(dsn_queue, dc,
                    _dispatch_qos_from_pp(dc->dc_priority), dc->dc_flags);
            _dispatch_release(dsn_queue);
        } while ((dc = next_dc));//找到相应的队列

        refs++;
    }

    if (dg_state & DISPATCH_GROUP_HAS_WAITERS) {
        _dispatch_wake_by_address(&dg->dg_gen);
    }

    if (refs) _dispatch_release_n(dg, refs);
}
  • 搜索_dispatch_continuation_async

这里就回到了我们熟悉的异步线程的下层函数,开始创建线程然后调用block。

  • 搜索dispatch_group_async
void
dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block)
{
    dispatch_retain(group);
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        block();
        dispatch_group_leave(group);
        dispatch_release(group);
    });
}

这段代码完全就是对dispatch_group_enterdispatch_group_leave的封装。
细心的同学可能还会发现一段dispatch_group_async的代码

#ifdef __BLOCKS__
void
dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq,
        dispatch_block_t db)
{
    dispatch_continuation_t dc = _dispatch_continuation_alloc();
    uintptr_t dc_flags = DC_FLAG_CONSUME | DC_FLAG_GROUP_ASYNC;
    dispatch_qos_t qos;

    qos = _dispatch_continuation_init(dc, dq, db, 0, dc_flags);
    _dispatch_continuation_group_async(dg, dq, dc, qos);
}
#endif
  • 接着查看_dispatch_continuation_group_async
DISPATCH_ALWAYS_INLINE
static inline void
_dispatch_continuation_group_async(dispatch_group_t dg, dispatch_queue_t dq,
        dispatch_continuation_t dc, dispatch_qos_t qos)
{
    dispatch_group_enter(dg);
    dc->dc_data = dg;
    _dispatch_continuation_async(dq, dc, qos, dc->dc_flags);
}

这里仅仅是开辟线程之前调用了dispatch_group_enter函数,并没有看见dispatch_group_leave函数,我们猜测是不是在执行完block的时候进行了一次dispatch_group_leave
在以下代码处打上断点,bt查看当前堆栈

  • bt

  • 搜索_dispatch_client_callout方法


    可以找到这么一个方法,当type = DISPATCH_GROUP_TYPEcallout之后会调用一次dispatch_group_leave唤醒当前线程。

至于为什么会调用_dispatch_continuation_with_group_invoke方法,我们接着往下看

  • 搜索_dispatch_continuation_with_group_invoke
    image.png

    _dispatch_continuation_invoke_inline之中找到了,_dispatch_continuation_invoke_inline是唤醒调用block的方法,此时经过条件判断,进来的是调度组就会执行_dispatch_continuation_with_group_invoke
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容