主进程中添加任务到GCD的main queue会卡死,而如果用生成的queue却正常运行:    dispatch_queue_t serialQueue = dispatch_queue_create("squeue", NULL);
//    dispatch_queue_t mainQueue = dispatch_get_main_queue();
  
    NSLog(@"Main Queue-->%@", dispatch_get_main_queue());    dispatch_sync(serialQueue, ^{ //如果用mainQueue就卡死
        NSLog(@"Task 1-->%@", [NSThread currentThread]);
    });在main()中执行没问题,如果dispatch_sync改用mainQueue的话就卡死了。squeue和mainQueue都是主线程里创建的串行队列,为什么前者正常,后者会卡死?是否可认为,sync函数本身是在主线程的主队列中执行,所以sync用mainQueue的话当然会死锁因为它自己就是mainQueue的第一个任务;
而用新生成的serialQueue,它的第一个任务就是添加的block,此时的mainQueue第一个任务只是sync,所以能顺利执行?

解决方案 »

  1.   

    主线程调用dispatch_sync会造成死锁,
    main_queue是串行队列,当queue调用sync函数块,会阻塞当前队列,等待block执行,但是这个block永远没有机会执行,当前队列就永远阻塞,造成死锁dispatch_sync(dispatch_get_main_queue() ^{ 
            NSLog(@"Task 1-->%@", [NSThread currentThread]);
        });
    http://stackoverflow.com/questions/19180661/sync-dispatch-on-current-queue/19181474#19181474
      

  2.   


    问题就是,这个在mainQueue里的block为什么不会执行?
    或者换个一个问法,在main()函数中,dispatch_queue_t squeue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);生成的squeue处于哪个线程?本来,个人理解为squeue应该在主线程里,当把block插入到squeue里,因为只有该block一个任务,所以是正常的。但如果有嵌套任务如下:
            
            dispatch_sync(squeue, ^{
                NSLog(@"Task 1-->%@", [NSThread currentThread]);
                dispatch_sync(squeue, ^{
                    NSLog(@"Task 2-->%@", [NSThread currentThread]);
                });
            });此时Task 2是squeue的第2个任务,它必须等到串行队列的第1个任务Task 1执行完才能执行;而squeue的第1个任务要想执行完,就要往下执行Task 2的block,所以2个任务的起始条件互为结果,造成线程的直接制约,死锁。
    另外,Task 1无论是sync还是async都会死锁,因为死锁的原因是任务调度顺序,而不是同步异步。以上是原先的理解,现在回到提问本身来。
    那么,同样是主线程里的串行队列dispatch_get_main_queue(),为什么就会卡死?dispatch_async(dispatch_get_main_queue() ^{ 
            NSLog(@"Task 1-->%@", [NSThread currentThread]);
        });
    NSRunLoop *rl = [NSRunLoop currentRunLoop];
    [rl run];为了撇清同异步影响,将sync换成async,同时为了让异步调用确实得到执行,运行一个runloop防止main()退出。
    在main()中执行会直接卡死。此时是异步调用,按理说block插入到mainQueue中不用等待结果就可以返回了吧,为何也会卡死?
       
      

  3.   


    问题就是,这个在mainQueue里的block为什么不会执行?
    或者换个一个问法,在main()函数中,dispatch_queue_t squeue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);生成的squeue处于哪个线程?本来,个人理解为squeue应该在主线程里,当把block插入到squeue里,因为只有该block一个任务,所以是正常的。但如果有嵌套任务如下:
            
            dispatch_sync(squeue, ^{
                NSLog(@"Task 1-->%@", [NSThread currentThread]);
                dispatch_sync(squeue, ^{
                    NSLog(@"Task 2-->%@", [NSThread currentThread]);
                });
            });此时Task 2是squeue的第2个任务,它必须等到串行队列的第1个任务Task 1执行完才能执行;而squeue的第1个任务要想执行完,就要往下执行Task 2的block,所以2个任务的起始条件互为结果,造成线程的直接制约,死锁。
    另外,Task 1无论是sync还是async都会死锁,因为死锁的原因是任务调度顺序,而不是同步异步。以上是原先的理解,现在回到提问本身来。
    那么,同样是主线程里的串行队列dispatch_get_main_queue(),为什么就会卡死?dispatch_async(dispatch_get_main_queue() ^{ 
            NSLog(@"Task 1-->%@", [NSThread currentThread]);
        });
    NSRunLoop *rl = [NSRunLoop currentRunLoop];
    [rl run];为了撇清同异步影响,将sync换成async,同时为了让异步调用确实得到执行,运行一个runloop防止main()退出。
    在main()中执行会直接卡死。此时是异步调用,按理说block插入到mainQueue中不用等待结果就可以返回了吧,为何也会卡死?
       
    以上关于异步调用mainQueue,本人的说法是错误的,由于看混了sync和async。
    更正:async调用mainQueue是正常的。请关注前面的问题。
      

  4.   

    问题描述得可能不太准确,重新整理。
    如下:
    //-------------------------------------------
    int main(void) {
    dispatch_queue_t queue = dispatch_queue_create(“com.somecompany.queue”, nil);
    dispatch_async(queue, ^{ //任务1
        [self goDoSomethingLongAndInvolved]; 
        dispatch_sync(queue, ^{ // 任务2
            NSLog(@"Situation 1"); 
        });
    });
    return 0;
    }
    这种场景下包了2层的的调用会死锁,任务1和任务2起始条件互为执行结果,形成直接制约,死锁。
    //-------------------------------------------
    int main(void) {
    dispatch_queue_t queue = dispatch_queue_create(“com.somecompany.queue”, nil);
    dispatch_sync(queue, ^{ // 任务1
            NSLog(@"Situation 1"); 
    });
    return 0;
    }
    这种场景正常。注意,这里只包了1层,queue是主线程生成的串行队列。
    //-------------------------------------------
    int main(void) {
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{ // 任务1
            NSLog(@"Situation 1"); 
    });
    return 0;
    }
    这种场景线程卡死。注意,这里只包了1层,queue是主队列。
    那么,对比上一场景,同样只包了1层同样是主线程里的串行队列同样sync调用,为何上一个正常这个卡死?
    结合第一个场景来推理,场景3卡死是因为sync函数调用时本身就运行在主队列中?
      

  5.   

    哈哈,你这个是最典型的互相等待导致锁死呀。
    调用的dispatch_sync函数一直得不到返回,main queue被阻塞,而我们的block又需要等待main queue来执行它,死锁愉快的产生了。
    慢慢领悟吧!!!
      

  6.   

    问题已在stackoverflow解决。我不是不理解互相等待导致的死锁,问题一开始就举例2层嵌套导致的死锁就是要说明我已经理解头尾互相等待会死锁。问题最后我根据3种情况推理出是否是因为sync()本身就运行在main()的主队列中,提问的核心在于想确认这个。
    而回答无一不在阐述main()中sync调用会导致死锁的现象力图解释头尾互相等待会死锁。其实如果有认真看提问的话,解答时说一句“因为sync就运行在主队列”或“语句都运行在主队列”就够了。
    我知道这是一个很基础的问题,但要的解答却不是网上那种囫囵吞枣的答案。同样的问题描述,还是老外比较认真,针对问题核心给予解答:
    Everything in your program runs on the main queue except for code that you explicitly dispatch onto another queue. Code on the main queue will always run on the main thread. Code dispatched on another queue may or may not run on the main thread.
    当然也可能是自己太菜,连所有语句都是运行在主队列上这种大家都普遍默认的常识都不懂,所以才会大费周章的解释死锁现象。因为以前用c,不太有iOS主队列的概念。