GCD让我死锁的死锁(Two)

本文目录:

  • 同步执行主队列(在主线程中)
  • 另几种死锁情况

本文参考文章链接:


GCD2之死锁

学习GCD,然后搞的我有点死锁了。下面是研究的一点死锁案例和原理...嗯...感觉还是总结的不太到位,可以看看第一个文章链接

同步执行主队列(在主线程中)

在主线程中,同步执行主队列,会造成死锁。

分析:在主线程,当前队列为主队列,然后使用同步执行提交任务到主队列,死锁。下面有详细的原理解释。

- (void)viewDidLoad {
    [super viewDidLoad];

    //主队列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    NSLog(@"开始"); 
    
    //异步提交一个任务到串行队列
    dispatch_sync(mainQueue, ^{

        NSLog(@"同步执行");

    });
    
    NSLog(@"结束");
}

输出:

2018-08-17 11:21:04.826284+0800 GCD[882:81994] 开始

然后就崩溃了

原理分析

  • 同步执行:必须执行完当前任务才能继续往下走,并且不具备开启多线程的能力,只能交给当前线程来执行(如果队列是主队列,会交给主线程来执行)。
  • 主队列,只能交给主线程来执行。平常的程序,不使用多线程的情况下,一般都是放在主队列中的。
  1. 现在,我们将viewDidLoad{}看作是一个任务,它是在主队列中的,交给主线程来执行的,它排在主队列的队首。

  2. 现在主线程正在执行将这个任务viewDidLoad{},主线程在这个任务里遇到了一个同步执行,同步执行必须将任务完成才能继续往下走( 这里的任务指NSLog(@"同步执行"); ),然后同步执行将这个任务提交给了主队列,想让主线程先完成这个任务。

  3. 但是,注意了,但是,主队列里面有一个任务viewDidLoad{}了,同步执行将这个任务( NSLog(@"同步执行"); )提交给主队列后,只能排在任务viewDidLoad{}后面。主线程必须执行完任务viewDidLoad{},才能执行任务( NSLog(@"同步执行"); ),但是同步执行要求必须先执行完任务( NSLog(@"同步执行"); ),才能继续往下走。主线程说,我得按顺序执行啊,执行完前面的任务,才能执行后面的;同步执行说,不行,就得先执行我的,才能继续下去。好吧,结果就这样卡住了,谁也执行不了。

这就是死锁。

怎么在当前情况下怎么解开这个锁呢?

  1. 改用异步执行。因为异步执行会立即返回,不管任务到底是怎么被执行的。过程:主线程先执行主队列里的任务viewDidLoad{},在这个任务里遇到了异步执行,异步执行立即返回,任务继续,输出NSLog(@"结束"); ,然后任务viewDidLoad{}执行完成;同时,在异步执行返回的同时,异步执行将任务( NSLog(@"同步执行"); )提交给了主队列,主队列在执行完viewDidLoad{}后,就执行任务( NSLog(@"同步执行"); ),输出NSLog(@"同步执行")。结束。

  2. 改用其它队列:使用 dispatch_queue_create 创建一个队列。同步执行将任务提交给一个其它的队列,这里同步执行当前线程,即主线程执行任务。主线程在执行任务viewDidLoad{}时,碰到了同步执行,同步执行必须执行完( NSLog(@"同步执行");)才能继续,同时这个任务提交给了其它的队列,主线程切换队列,先执行其它队列里的这个任务( NSLog(@"同步执行");),在切回到主队列继续执行任务viewDidLoad{}。

  3. 上两个方法混用,就不赘述了。

另几种死锁情况

  1. 嵌套两个同步执行,且同步执行的是同一个串行队列,会出现死锁

同步执行嵌套,同一个串行队列:

    dispatch_queue_t serialQueue = dispatch_queue_create("com.lai.www", DISPATCH_QUEUE_SERIAL);
    
    dispatch_sync(serialQueue, ^{
        
        NSLog(@"1 %@", [NSThread currentThread]);

        dispatch_sync(serialQueue, ^{
            NSLog(@"2 %@", [NSThread currentThread]);
        });

        NSLog(@"3 %@", [NSThread currentThread]);
        
    });
  1. 但如果两个串行队列不是同一个,就不会出现死锁。

同步执行嵌套,不为同一个串行队列,不会死锁:

    dispatch_queue_t serialQueue1 = dispatch_queue_create("com.lai.www", DISPATCH_QUEUE_SERIAL);
    
    dispatch_queue_t serialQueue2 = dispatch_queue_create("com.lai.www", DISPATCH_QUEUE_SERIAL);
    
    dispatch_sync(serialQueue1, ^{
        
        NSLog(@"1 %@", [NSThread currentThread]);
        
        dispatch_sync(serialQueue2, ^{
            NSLog(@"2 %@", [NSThread currentThread]);
        });

        NSLog(@"3 %@", [NSThread currentThread]);
        
    });
    
    NSLog(@"4 %@", [NSThread currentThread]);
  1. 上面这种情况不会出现死锁,而且输出按照顺序。这里我出现了疑惑,不是同步执行必须等到block的结果返回,才能继续吗?可以在同步执行里面,使用同步执行去执行吗?我再试验了一下,发现,里面的串行队列换成并发队列,也不会出现死锁。

同步执行嵌套,外面为串行队列,里面为并发队列,不会死锁:

    dispatch_queue_t serialQueue = dispatch_queue_create("com.lai.www", DISPATCH_QUEUE_SERIAL);
    
    dispatch_queue_t concurrentQueue = dispatch_queue_create("first", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_sync(serialQueue, ^{
        
        NSLog(@"1 %@", [NSThread currentThread]);
        
        dispatch_sync(concurrentQueue, ^{
            NSLog(@"2 %@", [NSThread currentThread]);
        });

        NSLog(@"3 %@", [NSThread currentThread]);
        
    });
    
    NSLog(@"4 %@", [NSThread currentThread]);
  1. 然后我又在别人的博客上发现了一种死锁...我越来越怀疑自己了...

外面是异步串行队列,里面是同步串行队列,串行队列为同一个,死锁:

dispatch_queue_t serialQueue = dispatch_queue_create("fff", DISPATCH_QUEUE_SERIAL);
NSLog(@"1");
dispatch_async(serialQueue, ^{
    NSLog(@"2");
    dispatch_sync(serialQueue, ^{  
        NSLog(@"3");
    });
    NSLog(@"4");
});
NSLog(@"5");

这种情况,也会发生死锁,死锁在里面的同步执行。分析:同一个串行队列,外面是异步,可以开启另一条线程,但是串行队列一次只能执行一个任务,所以里面的同步执行死锁了。


****然后我总结了一下,下面是我自己的理解,可能不对,烦请指正****。

  1. 在同步执行的任务里,是可以再异步或同步执行的

  2. 并发队列不会造成死锁

注意,并发队列不会造成死锁。****因为并发队列可以一次执行多个任务****。

  1. 只有串行队列会造成死锁,因为串行队列一次只能执行队列的一个任务,当你在执行这个任务时,又提交了一个任务到这个串行队列,并要求同步执行时,会出现死锁。

上面的第一个例子就是这样, 主队列(是串行队列)正在被主线程执行任务,这时要求同步执行,并提交了一个任务到主队列,出现死锁。

中间那个死锁的例子和上面的原理相同。

最后的一个死锁的例子。虽然外面是异步执行,但是串行队列要求执行完这个,才能执行下一个。异步执行的那个任务还没完,就要求同步执行下一个任务;串行队列的第一个任务还没出去呢,就要求执行第二个,这肯定不行。


再看另一个死锁的例子:

    dispatch_queue_t concurrentQueue = dispatch_queue_create("first", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_queue_t serialQueue = dispatch_queue_create("com.lai.www", DISPATCH_QUEUE_SERIAL);
    
    dispatch_sync(serialQueue, ^{
        
        NSLog(@"1 %@", [NSThread currentThread]);
        
        dispatch_sync(concurrentQueue, ^{
            
            NSLog(@"2 %@", [NSThread currentThread]);
            
            dispatch_sync(serialQueue, ^{
                
                NSLog(@"3 %@", [NSThread currentThread]);
                
            });
            
        });

    });

中间的换成异步执行就不会死锁:

    dispatch_sync(serialQueue, ^{
        
        NSLog(@"1 %@", [NSThread currentThread]);
        
        dispatch_async(concurrentQueue, ^{
            
            NSLog(@"2 %@", [NSThread currentThread]);
            
            dispatch_sync(serialQueue, ^{
                
                NSLog(@"3 %@", [NSThread currentThread]);
                
            });
            
        });

    });

我也是闲的...搞的我有点糊涂了,最后还是说,死锁得具体问题具体分析。

****总结一点,死锁归根到底,就是串行队列被阻塞了****。

大家可以看看这篇文章:理解GCD死锁

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

推荐阅读更多精彩内容