GCD避免死锁的三要素

平时总在用GCD,但你知不知道,GCD一不小心就会出现死锁,如果死锁在主线程上,整个程序就完了,所以避免死锁是我们则无旁贷的责任。

那我们先看看造成GCD死锁的三要素(以下内容是我个人总结,并写了一些测试用例,如有不对的地方,请大家指正 PS:我把GCD死锁分成 “普通死锁” ,“高级死锁”,"混合死锁")

普通死锁 必要条件

1.队列 串行队列:1 并行队列:0
2.调度方法 同步调用(dispatch_sync):1 异步调用(dispatch_async):0
3.同一个Q 当前所分发到的Q 和 "外部Q" 是否是同一个Q 同一个:1 不同:0

PS:"外部Q"是指
1.当前嵌套在外部的Q 如以下形式,Q1就是外部Q

dispatch_sync(Q1, ^{
     NSLog(@"b");
     dispatch_sync(Q2, ^{
            NSLog(@"c");
     });
  });)              

2.外部的方法执行时 所在的Q 如以下形式 dead1第二次运行时所在的Q是Q1 它就是外部Q

- (void)dead1{
    NSLog(@"不死1");
     __weak typeof (self) weakSelf = self;
     dispatch_sync(Q1, ^{
           NSLog(@"第二次运行死");
           [weakSelf dead1];
});}

#######结论: 如果三个条件同时满足 则死锁,如果其中一个不满足 不会死锁

高级死锁 必要条件

1.调度方法 同步阻塞调用(dispatch_barrier_sync):1 异步阻塞调用(dispatch_barrier_async):0
2.同一个Q 当前所分发到的Q 和 "外部Q" 是否是同一个Q 同一个:1 不同:0

#######结论: 如果两个条件同时满足 则死锁,如果其中一个不满足 不会死锁 (高级死锁主要针对dispatch_barrier而言)

混合死锁 必要条件

1.调度方法 同步阻塞调用(dispatch_barrier_sync)或同步调用(dispatch_sync):1 异步阻塞调用(dispatch_barrier_async)或异步调用(dispatch_async):0
2.同一个Q 当前所分发到的Q 和 "外部Q" 是否是同一个Q 同一个:1 不同:0

#######结论: 如果两个条件同时满足 则死锁,如果其中一个不满足 不会死锁 (混合死锁主要针对dispatch_barrier 和 dispatch_async,dispatch_sync嵌套调用而言)


以下是死锁测试用例

- (void)viewDidLoad 
{
     [super viewDidLoad];
    // 创建两个串行队列和一个并行队列
    _serialQueue = dispatch_queue_create("aabbcc", DISPATCH_QUEUE_SERIAL);
    _secondSerialQueue = dispatch_queue_create("ssss", DISPATCH_QUEUE_SERIAL);
    _concurrentQueue = dispatch_queue_create("dddd", DISPATCH_QUEUE_CONCURRENT); 
    [self dead1];
    [self dead2];
    [self dead3];
 }

一 普通死锁

- (void)dead1
{
    NSLog(@"不死1");
    __weak typeof (self) weakSelf = self;
    dispatch_sync(_serialQueue, ^{
        NSLog(@"第二次运行死");
        [weakSelf dead1];
    });
} 

PS:打印日志如下:
2015-10-29 16:46:35.611 DeadLockTest[19971:204243] 不死1
2015-10-29 16:46:35.612 DeadLockTest[19971:204243] 第二次运行死
2015-10-29 16:46:35.612 DeadLockTest[19971:204243] 不死1
原因 在[weakSelf dead1]; 循环调用方法本身时,它就在_serialQueue队列上运行,此时“dispatch_sync(_serialQueue, ^{}” 满足条件三,同一个Q _serialQueue上 同时又满足 串行Q 和 同步分发 所以在第二次运行时产生死锁。

- (void)dead2
{
    NSLog(@"不死1");
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"死锁");
    });
}    

PS:打印日志如下:
2015-10-29 16:52:45.435 DeadLockTest[20036:206574] 不死1
原因 dispatch_get_main_queue() 是主Q dead2本身就在主Q 上运行 符合同一个Q 并且同时符合2,3条件 所以死锁

二 高级死锁

//死在子线程
- (void)dead3
{
    //并行队列死锁
    NSLog(@"a");
    dispatch_async(_concurrentQueue, ^{
        NSLog(@"b");
        dispatch_barrier_sync(_concurrentQueue, ^{
             NSLog(@"c");
        });
    });
}

PS:打印日志如下:
2015-10-29 18:15:02.522 DeadLockTest[27790:256689] a
2015-10-29 18:15:05.919 DeadLockTest[27790:256851] b
原因 同时满足 1都是同一个Q _concurrentQueue 2同步分发 使用dispatch_barrier_sync 所以死锁

三 混合死锁

//混合模式,内部使用dispatch_sync 又是同一Q _concurrentQueue 死锁
- (void)dead4
{
    NSLog(@"不死1");
    dispatch_barrier_async(_concurrentQueue, ^{
        NSLog(@"不死2");
       dispatch_sync(_concurrentQueue, ^{
           NSLog(@"死在子线程上");
       });
    });
}

PS:打印日志如下:
2015-10-30 10:13:08.544 DeadLockTest[5346:35961] 不死1
2015-10-30 10:13:08.550 DeadLockTest[5346:36036] 不死2
原因 同时满足 1都是同一个Q _concurrentQueue 2同步分发 使用dispatch_sync 所以死锁

//混合模式,内部使用dispatch_barrier_sync 又是同一Q _concurrentQueue 死锁
- (void)dead5
{
    NSLog(@"不死1");
    dispatch_async(_concurrentQueue, ^{
        NSLog(@"不死2");
        dispatch_barrier_sync(_concurrentQueue, ^{
           NSLog(@"死在子线程上");
       });
    });
}

PS:打印日志如下:
2015-10-30 10:14:08.544 DeadLockTest[5346:35961] 不死1
2015-10-30 10:14:08.550 DeadLockTest[5346:36036] 不死2
原因 同时满足 1都是同一个Q _concurrentQueue 2同步分发 使用dispatch_barrier_sync 所以死锁


以下是非死锁测试用例

/*打破条件1  _concurrentQueue 是并行队列 不死锁 */
- (void)noDead1
{
    NSLog(@"a");
    dispatch_async(_concurrentQueue, ^{
        NSLog(@"b");
       dispatch_sync(_concurrentQueue, ^{
           NSLog(@"c");
       });
    });
}

PS:打印日志如下
2015-10-29 18:22:36.724 DeadLockTest[27922:261502] a
2015-10-29 18:22:36.725 DeadLockTest[27922:261633] b
2015-10-29 18:22:36.726 DeadLockTest[27922:261633] c

  /*虽然说三条日志都在主线程上执行,但是因为是在两个不同的队列上 打破条件3  
  不会死锁 _serialQueue和_secondSerialQueue 不是同一个队列*/
- (void)noDead2
{
    NSLog(@"不死1");
    dispatch_sync(_serialQueue, ^{
        NSLog(@"不死2");
        dispatch_sync(_secondSerialQueue, ^{
            NSLog(@"不死3");
        });
    });
}

PS:打印日志如下
2015-10-29 18:26:23.876 DeadLockTest[27977:263046] 不死1
2015-10-29 18:26:23.877 DeadLockTest[27977:263046] 不死2
2015-10-29 18:26:23.878 DeadLockTest[27977:263046] 不死3


以上就是对死锁的分析,如果掌握了这几个必要条件,赶快用下面的链接练练手吧,检验一下对不对
http://www.cnblogs.com/tangbinblog/p/4133481.html

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

推荐阅读更多精彩内容