GCD死鎖情況

造成死鎖的情況分析

第一種是:主隊(duì)列同步任務(wù)很容易造成死鎖,因?yàn)橹麝?duì)列是在主線程空閑時(shí)才會(huì)調(diào)度隊(duì)列中的任務(wù)在主線程上執(zhí)行.如果主線程不是空閑狀態(tài),那么主隊(duì)列中不論是同步任務(wù)還是異步任務(wù)都會(huì)死鎖,永遠(yuǎn)不會(huì)執(zhí)行.

- (void)gcdDemo1 
       NSLog(@"begin %@", [NSThreadcurrentThread]); 
      //  主隊(duì)列同步執(zhí)行任務(wù)  
       dispatch_sync(dispatch_get_main_queue(), ^{
              NSLog(@"%@", [NSThreadcurrentThread]);
        });   
        NSLog(@"end %@", [NSThreadcurrentThread]);
}
- (void)gcdDemo2 {
    // 1. 串行隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("cn.zh.queue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"begin %@", [NSThreadcurrentThread]);
    //  主隊(duì)列同步執(zhí)行任務(wù)通過外層嵌套子線程保證當(dāng)前函數(shù)中任務(wù)不需要等待主隊(duì)列任務(wù)執(zhí)行完.
    dispatch_async(queue, ^{ 
        dispatch_sync(dispatch_get_main_queue(), ^{ 
          NSLog(@"1%@", [NSThreadcurrentThread]);  
         });   
    });  
  //  由于主隊(duì)列中放置了同步任務(wù),通過上一步操作,表明主線程的任務(wù)必須要執(zhí)行完才能執(zhí)行下面的同步任務(wù)(也是主線程),但是下面的同步任務(wù)因?yàn)樯厦娴闹麝?duì)列同步任務(wù)需要等待主線程空閑才能執(zhí)行,相互等待,造成死鎖.
    dispatch_sync(queue, ^{ 
        NSLog(@"2%@", [NSThreadcurrentThread]);
    });
    NSLog(@"end %@", [NSThreadcurrentThread]); 
}

注意:如果上面的:

   dispatch_sync(queue, ^{ 
        NSLog(@"2%@", [NSThreadcurrentThread]);
    });

改成:

 dispatch_async(queue, ^{ 
        NSLog(@"2%@", [NSThreadcurrentThread]);
    });

執(zhí)行結(jié)果肯定永遠(yuǎn)是這個(gè)順序:

begin <NSThread: 0x7f89da4080d0>{number = 1, name = main}
end <NSThread: 0x7f89da4080d0>{number = 1, name = main}
1<NSThread: 0x7f89da4080d0>{number = 1, name = main}
2<NSThread: 0x7f89da710f20>{number = 2, name = (null)}

因?yàn)?上面的主隊(duì)列調(diào)度主線程的是同步任務(wù),需要立即執(zhí)行完才能執(zhí)行下面的操作,但是主線程目前還沒有空閑,需要執(zhí)行完本身gcdDemo2的NSLog(@"end %@", [NSThreadcurrentThread])才算完,所以begin —> end —>1 —>2


第二種是:

  • 串行隊(duì)列同步任務(wù)—>嵌套同步任務(wù)—>導(dǎo)致當(dāng)前線程死鎖.因?yàn)镃PU執(zhí)行到3的位置時(shí),因?yàn)槭峭饺蝿?wù),需要等待當(dāng)前線程(目前是主線程)執(zhí)行完,也即是2位置的外層嵌套的同步任務(wù).由于外層嵌套的同步任務(wù)又要等待3位置的同步任務(wù)執(zhí)行完,所以導(dǎo)致相互等待,死鎖.
- (void)gcdDemo4 {

    // 1. 串行隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("cn.zh.queue", DISPATCH_QUEUE_SERIAL);

    // 2. 串行隊(duì)列異步
    dispatch_sync(queue, ^{
        NSLog(@"begin %@", [NSThread currentThread]);

     // 3. 同步任務(wù)中嵌套同步任務(wù)會(huì)導(dǎo)致當(dāng)前主線程死鎖
     dispatch_sync(queue, ^{  
     NSLog(@"%@", [NSThread currentThread]);
    });
    NSLog(@"end %@", [NSThread currentThread]);   
 });
}
  • 串行隊(duì)列異步任務(wù)—>嵌套同步任務(wù)—>導(dǎo)致當(dāng)前線程死鎖.因?yàn)镃PU執(zhí)行到3的位置時(shí),因?yàn)槭峭饺蝿?wù),需要等待當(dāng)前線程(目前是子線程)執(zhí)行完,也即是2位置的外層嵌套的子線程的異步任務(wù).由于外層嵌套的子線程異步任務(wù)執(zhí)行時(shí)又要等待3位置的同步任務(wù)執(zhí)行完,所以導(dǎo)致相互等待,死鎖.
- (void)gcdDemo4 {
    // 1. 串行隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("cn.zh.queue", DISPATCH_QUEUE_SERIAL);
    // 2. 串行隊(duì)列異步
    dispatch_async(queue, ^{
        NSLog(@"begin %@", [NSThread currentThread]);
    // 3. 異步任務(wù)中嵌套同步任務(wù)會(huì)導(dǎo)致當(dāng)前子線程死鎖
        dispatch_sync(queue, ^{ 
        NSLog(@"%@", [NSThread currentThread]);
        });
    NSLog(@"end %@", [NSThread currentThread]);   
  });
}

注意:如果換成并行隊(duì)列就不會(huì)死鎖,因?yàn)椴⑿嘘?duì)列異步任務(wù)時(shí),分配了不同的子線程,不會(huì)在一條子線程上死鎖.


總結(jié):導(dǎo)致線程死鎖情況只需要考慮兩點(diǎn):1)是不是同一個(gè)線程上.2)是不是相互等待

容易導(dǎo)致死鎖的情況:
1)主隊(duì)列同步任務(wù),如果主線程上的執(zhí)行函數(shù)沒有用子線程去”包”一下,就會(huì)因?yàn)橹骶€程上的執(zhí)行函數(shù)BLOCK大任務(wù)與主隊(duì)列中需要調(diào)度到主線程的BLOCK任務(wù)相互等待,導(dǎo)致死鎖;

注意:主隊(duì)列只有在主線程空閑狀態(tài)才會(huì)將任務(wù)調(diào)度到主線程執(zhí)行,所以主隊(duì)列的異步任務(wù),也可能出現(xiàn)永遠(yuǎn)無法執(zhí)行的情況.

2)串行隊(duì)列同步任務(wù)嵌套同步任務(wù),如上演示的demo,會(huì)導(dǎo)致當(dāng)前線程死鎖;
串行隊(duì)列異步任務(wù)嵌套同步任務(wù),如上演示的demo,會(huì)導(dǎo)致當(dāng)前子線程死鎖;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容