GCD死锁的知识点

队列:负责调度任务

串行队列(Serial Dispatch Queue):一个接一个的调度任务,要等待上一个执行完,再执行下一个。
并行队列(Concurrent Dispatch Queue):可以同时调度多个任务,不需要上一个执行完,就能执行下一个
串行和并行针对的是队列
主队列在主线程中,所以在主队列中的任务一定是在主线程中执行的。但是主线程中可以有其他队列。既可以有串行队列也可以有并行队列。

线程 (同步和异步针对的是线程)

同步线程

阻塞当前线程,必须要等待同步线程中的任务执行完才能返回。
dispatch_sync(<#dispatch_queue_t  _Nonnull queue#>, <#^(void)block#>)
注意:
来自Apple 官方文档
Submits a block to the specified dispatch queue for synchronous execution. Unlike dispatch_async, this function does not return until the block has finished.

Calling this function and targeting the current queue results in deadlock.

Unlike with dispatch_async, no retain is performed on the target queue. Because calls to this function are synchronous, it "borrows" the reference of the caller. Moreover, no Block_copy is performed on the block.
As a performance optimization, this function executes blocks on the current thread whenever possible, with one obvious exception. Specifically, blocks submitted to the main dispatch queue always run on the main thread.

异步线程

不阻塞当前线程
This function is the fundamental mechanism for submitting blocks to a dispatch queue. Calls to this function always return immediately after the block has been submitted and never wait for the block to be invoked. The target queue determines whether the block is invoked serially or concurrently with respect to other blocks submitted to that same queue. Independent serial queues are processed concurrently with respect to each other.

GCD 导致死锁的2个案例

1、同步 主线程 主队列导致死锁

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

修改为一下代码,可解决死锁:
- (void)viewDidLoad {
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"解决死锁");
    });
}

导致死锁的原因:
首先,主线程中默认有一个主队列,viewDidLoad作为任务1,被放入了主队列,当执行同步线程时,block作为任务2,也被放入队列中,因为同步线程的一个特点:(Unlike dispatch_async, this function does not return until the block has finished),所以阻塞当前线程,并立马执行任务2。因为当前主队列中有两个任务(任务1(viewDidLoad) 和 任务2(block) ) ,并且任务1在队列的顶端,必须执行完毕,从队列出来才能执行任务2。任务1是不可能执行完成的,因为任务2是任务1的一部分,所以任务1不可能完成,也就导致任务1在顶端无法从队列中出来,任务2就卡在了队列中,也就无法执行完成。导致死锁。
解决死锁的原因:
dispatch_async 不会阻塞线程,无需等待block立即执行,就返回。所以任务1可以从队列中弹出,然后执行任务2.

2、异步线程同步将任务加入当前队列

- (void)viewDidLoad {
    dispatch_queue_t queue = dispatch_queue_create("serrial", DISPATCH_QUEUE_SERIAL);
    NSLog(@"打印1");
    dispatch_async(queue, ^{ // 任务1
        NSLog(@"打印2"); 
        dispatch_sync(queue, ^{ // 任务2
            NSLog(@"死锁");
        });
    });
    NSLog(@"打印3");
}
 打印1
 打印3
 打印2
 死锁
 解决方式1、
 - (void)viewDidLoad {
    dispatch_queue_t queue = dispatch_queue_create("serrial", DISPATCH_QUEUE_SERIAL);
    NSLog(@"打印1");
    dispatch_async(queue, ^{
        NSLog(@"打印2");
        dispatch_async(queue, ^{
            NSLog(@"解决死锁");
        });
    });
    NSLog(@"打印3");
}
解决方式2:
- (void)viewDidLoad {
    dispatch_queue_t queue = dispatch_queue_create("serrial", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue1 = dispatch_queue_create("serrial", DISPATCH_QUEUE_SERIAL);
    NSLog(@"打印1");
    dispatch_async(queue, ^{
        NSLog(@"打印2");
        dispatch_sync(queue1, ^{
            NSLog(@"解决死锁");
        });
    });
    NSLog(@"打印3");
}
解决方式3:
- (void)viewDidLoad {

    dispatch_queue_t queue = dispatch_queue_create("serrial", DISPATCH_QUEUE_CONCURRENT);
    
    NSLog(@"打印1");
    dispatch_async(queue, ^{
        NSLog(@"打印2");
        dispatch_sync(queue, ^{
            NSLog(@"解决死锁");
        });
    });
    NSLog(@"打印3");
}
 
死锁的原因
当前存在两个队列(主队列和queue),两个线程(主线程 子线程)。
打印1 和 打印4 是在主线程中执行的。打印2 是在子线程中执行的。
打印1执行完毕后,子线程开辟,打印2和打印4无先后。任务1(block1)加入queue队列,打印2,任务2(block2)加入队列,因为当前线程为同步线程,会阻塞当前线程,等到任务2的block执行完毕,才会往下执行结束任务1。这个时候队列是什么情况呢?队列里有两个任务,任务1和任务2,并且因为任务1是先进入队列的,根据FIFO原则,只有任务1执行完毕,任务1才能弹出队列,执行任务2,但是任务1要想执行完毕,就得执行任务2,因为任务2是任务1的一部分。这个时候的任务2在队列末尾等着 任务1滚出去,来完成任务。但是任务1又因为任务2在队列里等自己,所以任务1也无法完成。导致死锁。

总结

image.png

Apple 官方文档摘录:

Calling this function and targeting the current queue results in deadlock.
使用sync函数往当前串行队列中添加任务,会卡住当前的串行队列(产生死锁)
代码解释:
死锁:
dispatch_queue_create("serrial", DISPATCH_QUEUE_SERIAL);
    NSLog(@"打印1");
    dispatch_async(queue, ^{ 
        NSLog(@"打印2");
        dispatch_sync(queue, ^{ // sync 函数往所在的queue中添加任务
            NSLog(@"死锁");
        });
    });

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

推荐阅读更多精彩内容

  • 1.dispatch_after 工作起来就像一个延迟版的 dispatch_async 。你依然不能控制实际的执...
    伏特加阅读 233评论 0 0
  • 串联GCD知识点 dispatch_queue_t // 声明一个queue dispatch_queue_cre...
    陈_振阅读 216评论 0 0
  • 一、知识结构分析 多线程之间的关系 pthread是POSIX线程的API NSThread是Cocoa对pthr...
    huoshe2019阅读 476评论 0 4
  • 队列(Dispatch Queue) 串行队列(Serial Dispatch Queue):在一个线程中一个接一...
    贵族小猫钓鱼阅读 334评论 0 0
  • 1、网络层和业务层的对接设计 使用哪种交互模式来和业务层对接 : 使用Delegate为主,目的是为了(1)减少代...
    雷3雷阅读 397评论 0 0