美文网首页
OC底层原理探索—GCD(中)

OC底层原理探索—GCD(中)

作者: 十年开发初学者 | 来源:发表于2021-08-17 15:16 被阅读0次

    GCD死锁

    
    - (void)deadlock {
          // 主线程
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"1");
        });
    }
    
    

    进入dispatch_sync->_dispatch_sync_f->_dispatch_sync_f_inline

    image.png
    通过符号断点会进入_dispatch_barrier_sync_f方法,这也和我们的判断一致dq_width == 1代表串行队列,进入_dispatch_barrier_sync_f
    image.png
    进入_dispatch_barrier_sync_f_inline
    image.png
    进入_dispatch_sync_f_slow
    DISPATCH_NOINLINE
    static void
    _dispatch_sync_f_slow(dispatch_queue_class_t top_dqu, void *ctxt,
            dispatch_function_t func, uintptr_t top_dc_flags,
            dispatch_queue_class_t dqu, uintptr_t dc_flags)
    {
        dispatch_queue_t top_dq = top_dqu._dq;
        dispatch_queue_t dq = dqu._dq;
        if (unlikely(!dq->do_targetq)) {
            return _dispatch_sync_function_invoke(dq, ctxt, func);
        }
    
        pthread_priority_t pp = _dispatch_get_priority();
        struct dispatch_sync_context_s dsc = {
            .dc_flags    = DC_FLAG_SYNC_WAITER | dc_flags,
            .dc_func     = _dispatch_async_and_wait_invoke,
            .dc_ctxt     = &dsc,
            .dc_other    = top_dq,
            .dc_priority = pp | _PTHREAD_PRIORITY_ENFORCE_FLAG,
            .dc_voucher  = _voucher_get(),
            .dsc_func    = func,
            .dsc_ctxt    = ctxt,
            .dsc_waiter  = _dispatch_tid_self(),
        };
    //向队列中添加任务
        _dispatch_trace_item_push(top_dq, &dsc);
        __DISPATCH_WAIT_FOR_QUEUE__(&dsc, dq);
    
        if (dsc.dsc_func == NULL) {
            // dsc_func being cleared means that the block ran on another thread ie.
            // case (2) as listed in _dispatch_async_and_wait_f_slow.
            dispatch_queue_t stop_dq = dsc.dc_other;
            return _dispatch_sync_complete_recurse(top_dq, stop_dq, top_dc_flags);
        }
    
        _dispatch_introspection_sync_begin(top_dq);
        _dispatch_trace_item_pop(top_dq, &dsc);
        _dispatch_sync_invoke_and_complete_recurse(top_dq, ctxt, func,top_dc_flags
                DISPATCH_TRACE_ARG(&dsc));
    }
    

    走到这一不我们不知道哪里引起的死锁,运行程序

    image.png
    发现是在这行代码__DISPATCH_WAIT_FOR_QUEUE__引起的崩溃,进入__DISPATCH_WAIT_FOR_QUEUE__
    image.png
    进入_dq_state_drain_locked_by->_dispatch_lock_is_locked_by查看
    image.png
    DLOCK_OWNER_MASK是个很大的数,也就是lock_value ^ tid = 0时,才会返回0,也就是说此时使用的队列和当前等待的队列是同一个队列。
    【结论】死锁是当前的队列处于等待状态,而又有了新任务过来需要使用这个队列调度,这样就产生了相互等待,进而产生死锁

    GCD 单例

       static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            
        });
    

    进入dispatch_once

    image.png
    进入dispatch_once_f,这里有三个参数onceToken、函数任务、任务的封装
    image.png
    进入_dispatch_once_gate_tryenter
    image.png
    这里为了保证线程的安全性,通过_dispatch_lock_value_for_self上了把锁,保证多线程的安全,如果返回YES,则会去执行_dispatch_once_callout方法,进入该方法
    image.png
    进入_dispatch_once_gate_broadcast
    image.png
    onceToken进行原子对比,如果没有执行过,设置为done,并对_dispatch_once_gate_tryenter中的锁进行处理。

    回到dispatch_once_f方法

    image.png
    在代码的最后有个_dispatch_once_wait方法
    image.png
    这里主要是为处理在多线程的没有获取到锁的情况下,就会调用_dispatch_once_wait方法进行等待,该方法中内部开启了自旋锁,内部进行原子处理,如果发现其他线程设置了done,则放弃处理

    异步函数

    image.png
    这里是一个单例方法,我们进入_dispatch_root_queues_init_once方法
    image.png
    在上篇文章中,我们探索到了异步函数的任务,最终被统一设置为workq_cb
    image.png
    接着通过workloop工作循环调用,也就是说不是立即调用,而是通过os完成调用,也就说明异步调用的关键是在需要执行的时候能够获取对应的方法,进行异步处理,而同步函数是直接调用。
    那么异步函数的调用到底是在什么时候调用的,返回上一个方法_dispatch_root_queue_poke_slow
    如果是全局队列会进入以下方法
    image.png
    对线程池进行处理,从线程池中获取线程,执行任务,同时判断线程池的变化。
    image.png
    remaining,可以理解为当前可用线程数,当线程数等于0时,线程池已满pthread pool is full,直接return。底层通过pthread开辟线程
    image.png
    也就是_dispatch_worker_thread2是通过pthread完成oc_atmoic原子触发。

    相关文章

      网友评论

          本文标题:OC底层原理探索—GCD(中)

          本文链接:https://www.haomeiwen.com/subject/pzfibltx.html