关于向主线程添加同步任务造成死锁的思考

有这样一个例子,即在主线程开启同步任务死锁的例子:

NSLog(@"1"); // 任务1
dispatch_sync(dispatch_get_main_queue(), ^{
   NSLog(@"2"); // 任务2
});
NSLog(@"3"); // 任务3

关于这个例子如何会死锁,网上也有很详细的解释。不过可能对于某些基础不是很扎实的同学来说,有些地方不太容易理解。这里,我说一下自己的理解,希望对你有所帮助。

如大家所说,造成这种死锁的原因在于:

1.dispatch_sync,同步执行;
2.dispatch_get_main_queue(),主队列。这里先说一下为什么会造成死锁,后面再介绍其他内容;

第一点,先让我们来看看dispatch_sync和dispatch_async,按照字面意思理解前者是同步的,后者是异步的。苹果给出的文档中,dispatch_sync的解释是:Submits a block for synchronous execution on a dispatch queue。翻译之后就是,向队列中,提交一个同步执行的block。同时,文档中也有这样一句话:dispatch_sync() will not return until the block has finished。就是说,只有当block中的内容执行完之后,才会返回之前插入的地方继续执行。

相对应的,dispatch_async的解释是:Submits a block for asynchronous execution on a dispatch queue。翻译之后就是,向队列中,提交一个异步执行的block。同样的,此时不会等待block的执行,会直接执行之后的代码,而将block交给其他线程。这里暂且不说,后面再聊。

第二点,dispatch_get_main_queue(),苹果给出的解释是:Returns the default queue that is bound to the main thread。也就是说,它返回了依靠主线程来执行任务的队列。这里涉及到Runloop,简单理解就是,iOS程序有一个一直在执行的线程,这个线程会一直运行直到被叫停。这个线程和主队列是绑定的,就是用来执行主队列的任务。

那么现在把它们放在一起考虑,系统一直在顺序执行主队列的任务(通过主线程),此时阻塞主线程(dispatch_sync)向主队列队尾添加一个任务(不知道主队列此时有没有任务在执行,不care)。dispatch_sync必须等到block执行完才会返回当前线程(主线程)继续往下执行,当然下一个任务仍然来自于主队列。那么,此时主线程在等待主队列给出下一个任务(因为主线程与主队列是绑定的,只能根据FIFO原则顺序执行主队列的任务);可是主队列也在等待,它在等待主线程将block执行完成才会给主线程另外一个任务。主线程和主队列在互相等待,那么就造成了死锁。

这个原理确实很绕口,在看了很多博客之后,总算有点儿眉目。本来我是无法理解为什么会造成死锁的,直到想通了上面关节,就是主线程和主队列互相等待。在想通这些的过程中,我做了另外的工作来证实这种想法,或者说另外的这些让我想通了这个关节。让我们来看另外两个例子。


这里有一个不会死锁的例子:

    NSLog(@"1,NSThread:%@",[NSThread currentThread]); // 任务1
    dispatch_async(queueC, ^{
        NSLog(@"2,NSThread:%@",[NSThread currentThread]); // 任务2
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"3,NSThread:%@",[NSThread currentThread]); // 任务3
        });
        NSLog(@"4,NSThread:%@",[NSThread currentThread]); // 任务4
    });
    NSLog(@"5,NSThread:%@",[NSThread currentThread]); // 任务5

输出结果是:

image.png

在这个例子中,用到了 dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"3,NSThread:%@",[NSThread currentThread]); // 任务3 });然而并没有出现线程死锁现象,控制台正常打印了1 5 2 3 4 。那么为什么这里不会造成死锁呢?原因就在于dispatch_sync是阻塞了当前线程来给后面队列添加任务。也就是说,在这里,dispatch_sync阻塞了number = 3 的线程,将block添加入主队列,之后由主线程(与主队列绑定)执行打印任务。接着完成之后,再由*number = 3 *的线程执行任务4,那么当然不会造成线程死锁。


下面有一个会死锁的例子:

    dispatch_queue_t queueS = dispatch_queue_create("com.demo.serialQueue", DISPATCH_QUEUE_SERIAL); // 串行队列
     NSLog(@"1,NSThread:%@",[NSThread currentThread]); // 任务1
    dispatch_async(queueS, ^{
        NSLog(@"2,NSThread:%@",[NSThread currentThread]); // 任务2
        dispatch_sync(queueS, ^{
            NSLog(@"3,NSThread:%@",[NSThread currentThread]); // 任务3
        });
        NSLog(@"4,NSThread:%@",[NSThread currentThread]); // 任务4
    });
    NSLog(@"5,NSThread:%@",[NSThread currentThread]); // 任务5

它的输出是:

image.png

我们看到,它在执行到 dispatch_sync(queueS, ^{ NSLog(@"3,NSThread:%@",[NSThread currentThread]); // 任务3 });的时候,出现了死锁,回头看一下它的打印结果,任务1和任务5都是主线程执行的,而任务2是number = 3 的线程执行的,也就是说,dispatch_sync阻塞了number = 3 的线程,同时,这个线程执行队列queueS里面的任务**。这就等价于在主线程向主队列同步插入block造成死锁,因为线程和队列相互等待。


弄清楚线程和队列的关系,这个问题就变得很简单了不是吗?

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

推荐阅读更多精彩内容