美文网首页
GCD的串行队列同步死锁问题

GCD的串行队列同步死锁问题

作者: 我才是臭吉吉 | 来源:发表于2019-08-08 11:37 被阅读0次

《Effective Objective-C 2.0》中“第46条:不要使用dispatch_get_current_queue”笔记

我们都知道,在串行队列的同步任务中,再次向其中派发同步任务会造成死锁(向主队列派发同步任务的死锁就是这样)。但是,如果是下面这样呢?

dispatch_queue_t queueA = dispatch_queue_create("com.jiji.serialQueueA", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queueB = dispatch_queue_create("com.jiji.serialQueueB", DISPATCH_QUEUE_SERIAL);

dispatch_sync(queueA, ^{
    // 向queueB中派发同步任务
    dispatch_sync(queueB, ^{
        // 向queueA中派发同步任务
        dispatch_sync(queueA, ^{
            NSLog(@"inner----");
        });
    });
    NSLog(@"outer-=-=-=-=-=-=");
});

结果同样死锁。这是因为最内部派发到queueA中的任务需要按队列的方式,等待先入队的最外层任务执行完成,但最外层任务被最内部的任务阻塞无法继续执行,故导致死锁。这在道理上与最简单的死锁没有区别。

但是,当我们想要使用dispatch_get_current_queue函数,对内部执行队列进行区分,防止死锁时,可以发现此方法早已被标记为了deprecated。也就是说,此函数返回的队列不能作为任务执行队列的判断依据。

故数组建议我们使用dispatch_queue_set_specific函数,对队列绑定相关数据。在派发的任务执行时,动态取出绑定数据来判定当前的执行队列**。

直接看对比示例:

// 将queueB的目标队列设置为queueA,即queueB中的任务被派发到queueA中执行
dispatch_set_target_queue(queueB, queueA);

// 给指定队列绑定相关数据(使用键值对的方式)
static int kQueueSpecific;
CFStringRef queueSpecificValue = CFSTR("queueA");
dispatch_queue_set_specific(queueA,
                            &kQueueSpecific,
                            (void *)queueSpecificValue,
                            (dispatch_function_t)CFRelease);

dispatch_sync(queueB, ^{
    dispatch_block_t block = ^ {
        NSLog(@"hahahahaha~~");
    };
    
    dispatch_queue_t currentQueue = dispatch_get_current_queue();
    if (currentQueue == queueA) {
        NSLog(@"currentQueue == queueA");
    } else {
        NSLog(@"currentQueue == queueB");
    }
    
    // 在当前队列中取出绑定的相关数据
    CFStringRef retrievedValue = dispatch_get_specific(&kQueueSpecific);
    
    if (retrievedValue) {
        // 存在相关值,即当前就在绑定的队列中执行,不要再向那个队列派发同步任务,会死锁
        NSLog(@"in queueA");
        block();
    } else {
        // 不存在,证明执行不在指定的那个队列中,可以派发同步任务
        NSLog(@"NOT in queueA");
        dispatch_sync(queueA, block);
    }
});
NSLog(@"finish!!!!");

执行结果:

LockTest[19151:825723] currentQueue == queueB
LockTest[19151:825723] in queueA
LockTest[19151:825723] hahahahaha~~
LockTest[19151:825723] finish!!!!

可以看出,由于设置了目标队列,实际上是有queueA执行派发任务。但是dispatch_get_current_queue只能反映出原始派发任务的队列,而通过dispatch_get_specific函数取到的绑定数据却是根据真实执行任务的队列获取到。故在同步派发任务时,为了防止死锁,可以使用dispatch_queue_set_specificdispatch_get_specific配对,来识别当前执行任务的队列**。

这就是不要使用dispatch_get_current_queue的原因。

相关文章

  • 2021--- GCD

    gcd同步,异步,串行队列,并发队列,全局队列,主队列,以及死锁。 1、gcd队列阻塞问题[https://www...

  • 2022-11-17 08多线程

    GCD 同步串行 死锁!,会导致队列引起循环等待 没有问题 同步并发 答案:12345 产生死锁 异步串行 异步并...

  • GCD 细细的读

    目录 前言 为什么选择GCD? 串行队列、并行队列、同步、异步 线程死锁解析 DispatchQueue的使用 D...

  • GCD 死锁

    GCD死锁 同步 异步 串行 并发

  • GCD的串行队列同步死锁问题

    《Effective Objective-C 2.0》中“第46条:不要使用dispatch_get_curren...

  • GCD死锁

    GCD死锁原因 GCD死锁的原因是队列阻塞,而不是线程阻塞! 串行和并行 串行和并行都是相对于队列而言的-队列(负...

  • GCD

    1、同步串行队列 2、同步并行队列 3、异步串行队列 4、异步并行队列 5、死锁 主线程中创建同步串行队列 主线程...

  • GCD 同步+串行和同步+主队列的疑惑

    gcd详解转发 新的读者可能在 同步执行+串行队列 与 同步执行+主队列 (前者可以正常执行,后者产生死锁)会产生...

  • 多线程

    iOS中的几种多线程GCD1、GCD分为任务和队列,任务(同步,异步)队列(串行,并发),同步串行,同步主队列的情...

  • iOS多线程(一)

    多线程涉及到的概念: 进程,线程,主线程,任务,队列,死锁,串行,并行,同步,异步,GCD,NSOperation...

网友评论

      本文标题:GCD的串行队列同步死锁问题

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