一直以来对dispatch_sync的误区

提出疑问

之前看过下面一段话:
权威书籍的讲解
所以我一直对dispatch_sync的理解就是制定到一个dispatch queue里面去执行一段代码,当时我就在想那么它与dispatch_async的区别是什么,难道只有一个是阻塞当前线程,一个不阻塞吗?

于是我写了一个demo测试了一下:

1 同步追加到主队列中

dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"1 %@",[NSThread currentThread]); // 任务2
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"2 %@",[NSThread currentThread]); 
            // 3 {number = 1, name = main}
        });
    });

2 同步追加到其他队列中

dispatch_queue_t queue = dispatch_queue_create("com.soon.lixiaolong", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"1 %@",[NSThread currentThread]); // 任务1 {number = 4, name = null}
        dispatch_sync(queue, ^{
            NSLog(@"2 %@",[NSThread currentThread]); // 任务2
            // 2 {number = 4, name = null}
        });
    });

可以很明显的看到同步到主线程是可以在主线程执行block的,但是同步到其他线程的时候却是在当前线程执行

于是我去查看源码

源码中是这样写的:

#ifdef __BLOCKS__
void
dispatch_sync(dispatch_queue_t dq, void (^work)(void))
{
    struct Block_basic *bb = (void *)work;
    dispatch_sync_f(dq, work, (dispatch_function_t)bb->Block_invoke);
}
#endif

DISPATCH_NOINLINE
void
dispatch_sync_f(dispatch_queue_t dq, void *ctxt, dispatch_function_t func)
{
    typeof(dq->dq_running) prev_cnt;
    dispatch_queue_t old_dq;

    if (dq->dq_width == 1) {
        return dispatch_barrier_sync_f(dq, ctxt, func);
    }

    // 1) ensure that this thread hasn't enqueued anything ahead of this call
    // 2) the queue is not suspended
    if (slowpath(dq->dq_items_tail) || slowpath(DISPATCH_OBJECT_SUSPENDED(dq))) {
        _dispatch_sync_f_slow(dq);
    } else {
        prev_cnt = dispatch_atomic_add(&dq->dq_running, 2) - 2;

        if (slowpath(prev_cnt & 1)) {
            if (dispatch_atomic_sub(&dq->dq_running, 2) == 0) {
                _dispatch_wakeup(dq);
            }
            _dispatch_sync_f_slow(dq);
        }
    }

    old_dq = _dispatch_thread_getspecific(dispatch_queue_key);
    _dispatch_thread_setspecific(dispatch_queue_key, dq);
    func(ctxt);
    _dispatch_workitem_inc();
    _dispatch_thread_setspecific(dispatch_queue_key, old_dq);

    if (slowpath(dispatch_atomic_sub(&dq->dq_running, 2) == 0)) {
        _dispatch_wakeup(dq);
    }
}

看到当dq的dq_width等于1的时候会执行dispatch_barrier_sync_f方法,反而就直接在当前线程执行func,dq_width等于1是主队列,只有主队列的位宽才是1

结语

在学习的时候还是要多实践,不能对网上的结论信以为真。

你可能感兴趣的:(iOS,ios多线程)