iOS GCD死锁底层探究和造成死锁的条件

平常面试中总会遇见GCD死锁的问题,那些情况下会造成死锁呢,先看一下CGD死锁崩溃的核心源码

 __DISPATCH_WAIT_FOR_QUEUE__(dispatch_sync_context_t dsc, dispatch_queue_t dq)
{
    uint64_t dq_state = _dispatch_wait_prepare(dq);
    if (unlikely(_dq_state_drain_locked_by(dq_state, dsc->dsc_waiter))) {
        DISPATCH_CLIENT_CRASH((uintptr_t)dq_state,
                "dispatch_sync called on queue"
                "already owned by current thread");
    }  

从上面代码中我们知道,当if条件为真时就会进入crash(这里崩溃的原因这两句英文已经解释了),那什么情况下if条件为真呢,点击_dispatch_lock_is_locked_by我们进一步分析

_dispatch_lock_is_locked_by(dispatch_lock lock_value, dispatch_tid tid)
{
    //lock_value: 当前队列
    //tid: 当前线程
    // equivalent to _dispatch_lock_owner(lock_value) == tid
    return ((lock_value ^ tid) & DLOCK_OWNER_MASK) == 0;
}

lock_value 当前传进来的队列,
tid 当前所在的线程
DLOCK_OWNER_MASK: 宏 ((dispatch_lock)0xfffffffc)一个很大的数字

分析 ((lock_value ^ tid) & DLOCK_OWNER_MASK) == 0
当一个数 &(与上) DLOCK_OWNER_MASK == 0 那这个数一定是0, 所以(lock_value ^ tid) 为0
(lock_value ^(异或) tid) 为0 也就说明 lock_value 和 tid 相等,也就是当前的队列和当前的线程要有关联 并是不是意思上的相等。(可以理解为同一个线程下同一个队列)
((lock_value ^ tid) & DLOCK_OWNER_MASK) == 0 成立时,if条件为真就会促发崩溃 。

从上可以得出一个结论:

在当前线程中同步(sync)的向同一个串行队列添加任务时就会死锁崩溃。

举几个死锁例子来深刻理解上述结论的意思:

以下代码都在viewDidLoad中执行

- (void)viewDidLoad {
    [super viewDidLoad];

    //结论:在当前线程中同步(sync)的向同一个串行队列添加任务时就会死锁崩溃。
    
    //例子1
    dispatch_sync(dispatch_get_main_queue(), ^{
        1 sync(同步)
        2 和 viewDidLoad 都是主线程 
        3 和 viewDidLoad 都是主队列 dispatch_get_main_queue
        4 主队列都是 串行队列
    });
  
    //例子2
    dispatch_queue_t lrQueue = dispatch_queue_create("xx", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(lrQueue, ^{
        当前主线程
        dispatch_sync(lrQueue, ^{
             1 添加的任务为同步 sync
             2 都是同一个串行队列 lrQueue
             3 都在同一个线程中
        });
    });
    
    //例子3
    dispatch_async(lrQueue, ^{
        当前子线程
        dispatch_sync(lrQueue, ^{
            1 添加的任务为同步 sync
            2 都是同一个串行队列 lrQueue
            3 添加的任务都在同一个子线程中, sync是不具备开启线程的能力的
        });
    });
    
   //例子4
    dispatch_sync(lrQueue, ^{
        //当前主线程
        dispatch_sync(dispatch_get_main_queue(), ^{
             1 添加的任务为同步 sync
             2 这里是 dispatch_get_main_queue 主队列,和 viewDidLoad 的队列相等    
             3 都在同一个主线程中
        });
    });

  修改一下例子4 
    dispatch_async(lrQueue, ^{
        当前子线程
        dispatch_sync(dispatch_get_main_queue(), ^{
            1 添加的任务为同步 sync
            2 这里是 dispatch_get_main_queue 主队列,和 viewDidLoad的队列相等
            3 viewDidLoad 是在主线程, 但是添加的任务是在子线程中 (条件不满足)
            4 sync是不会开启线程的 async才会开启线程

            所以条件不满足不是同一个线程 不会崩溃
        });
    });
}

综上只满足 在同一个线程中,同步的向同一个串行队列中添加任务就会崩溃。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容