iOS gcd線(xiàn)程死鎖問(wèn)題

同步異步?jīng)Q定是否具備開(kāi)啟線(xiàn)程的能力
串行并行決定代碼執(zhí)行的先后順序

先看下這幾個(gè)場(chǎng)景,每個(gè)場(chǎng)景中的代碼執(zhí)行后會(huì)打印什么,為什么?

場(chǎng)景一:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self test1];
}

-(void)test1{
//    主隊(duì)列 串行隊(duì)列
    dispatch_queue_t queue = dispatch_get_main_queue();
    NSLog(@"任務(wù)1");
//    同步任務(wù)
    dispatch_sync(queue, ^{
        NSLog(@"任務(wù)2");
    });
    NSLog(@"任務(wù)3");
}

@end

答案:會(huì)打印任務(wù)1,然后程序奔潰


截屏2020-07-06 14.23.24.png

原因:由于整個(gè)viewDidLoad方法是先加入到主隊(duì)列中的,然后將viewDidLoad方法中的代碼從隊(duì)列中取出來(lái)一步步執(zhí)行,當(dāng)執(zhí)行到dispatch_sync時(shí),就會(huì)將任務(wù)2的代碼加入到主隊(duì)列中,由于主隊(duì)列是串行隊(duì)列,所以必須要讓先從主隊(duì)列中取出來(lái)的viewDidLoad方法中的所有代碼執(zhí)行完才能取出后面加入到主隊(duì)列中的任務(wù)2代碼來(lái)執(zhí)行,但dispatch_sync同步任務(wù)的特點(diǎn)是立即要在當(dāng)前線(xiàn)程也就是主線(xiàn)程中執(zhí)行任務(wù)2中的代碼,這樣就形成了互相等待的僵局,這就是死鎖!

場(chǎng)景二:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self test1];
}

-(void)test1{
//    主隊(duì)列 串行隊(duì)列
    dispatch_queue_t queue = dispatch_get_main_queue();
    NSLog(@"任務(wù)1");
//    異步任務(wù)
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)2");
    });
    NSLog(@"任務(wù)3");
}

@end

答案:結(jié)果打印任務(wù)1、任務(wù)3、任務(wù)2,程序正常運(yùn)行


截屏2020-07-06 14.25.33.png

原因:在執(zhí)行主隊(duì)列中的viewDidLoad方法時(shí),碰到dispatch_async時(shí)也會(huì)將任務(wù)2中的代碼加入到主隊(duì)列中,但不同的是dispatch_async并不要求立馬執(zhí)行,可以延后執(zhí)行,這樣viewDidLoad方法執(zhí)行完后再?gòu)闹麝?duì)列中取出剛加入的任務(wù)2代碼,就不會(huì)造成互相等待的情況了

場(chǎng)景三:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self test1];
}

-(void)test1{
//    手動(dòng)創(chuàng)建的串行隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"任務(wù)1");
//    同步任務(wù)
    dispatch_sync(queue, ^{
        NSLog(@"任務(wù)2");
    });
    NSLog(@"任務(wù)3");
}

答案:結(jié)果打印任務(wù)1、任務(wù)2、任務(wù)3,程序正常運(yùn)行


截屏2020-07-06 14.38.29.png

原因:在執(zhí)行主隊(duì)列中的viewDidLoad方法時(shí),碰到dispatch_sync時(shí)就會(huì)將任務(wù)2中的代碼加入到手動(dòng)創(chuàng)建的串行隊(duì)列中,同步任務(wù)會(huì)讓任務(wù)中代碼立即執(zhí)行,由于任務(wù)2中的代碼是在其他的串行隊(duì)列中執(zhí)行,和主線(xiàn)程沒(méi)有關(guān)系,所以就優(yōu)先執(zhí)行任務(wù)2中的代碼,最后執(zhí)行任務(wù)3

場(chǎng)景四:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self test1];
}

-(void)test1{
//    手動(dòng)創(chuàng)建的串行隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"任務(wù)1");
//    異步任務(wù)
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)2");
    });
    NSLog(@"任務(wù)3");
}

答案:結(jié)果打印任務(wù)1、任務(wù)2、任務(wù)3(或者任務(wù)1、任務(wù)3、任務(wù)2),程序正常運(yùn)行


截屏2020-07-06 14.46.20.png

原因:在執(zhí)行主隊(duì)列中的viewDidLoad方法時(shí),碰到dispatch_async時(shí)就會(huì)將任務(wù)2中的代碼加入到手動(dòng)創(chuàng)建的串行隊(duì)列中,由于任務(wù)2和任務(wù)3不在同一個(gè)隊(duì)列中,而且任務(wù)2又是異步執(zhí)行,會(huì)創(chuàng)建子線(xiàn)程,所以任務(wù)2和任務(wù)3是并發(fā)執(zhí)行的,因此打印結(jié)果會(huì)有兩種情況

場(chǎng)景五:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self test1];
}

-(void)test1{
//    手動(dòng)創(chuàng)建的串行隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    NSLog(@"任務(wù)1");
//    異步任務(wù)
    dispatch_async(queue, ^{  // block1
        NSLog(@"任務(wù)2");
//        同步任務(wù)
        dispatch_sync(queue, ^{  // block2
            NSLog(@"任務(wù)3");
        });
        NSLog(@"任務(wù)4");
    });
    NSLog(@"任務(wù)5");
}

答案:結(jié)果打印任務(wù)1、任務(wù)2(或者任務(wù)1、任務(wù)5、任務(wù)2)程序奔潰,產(chǎn)生死鎖


截屏2020-07-06 15.01.55.png

原因:在執(zhí)行主隊(duì)列中的viewDidLoad方法時(shí),碰到dispatch_async時(shí)就會(huì)將block1中的代碼加入到手動(dòng)創(chuàng)建的串行隊(duì)列中,由于任務(wù)2和任務(wù)5不在同一個(gè)隊(duì)列中,而且任務(wù)2又是異步執(zhí)行,會(huì)創(chuàng)建子線(xiàn)程,所以任務(wù)2和任務(wù)5是并發(fā)執(zhí)行的,因此打印結(jié)果會(huì)有兩種情況,當(dāng)block1在執(zhí)行任務(wù)2的時(shí)候,碰到dispatch_sync就會(huì)將block2加入到當(dāng)前串行隊(duì)列queue中,由于dispatch_sync是同步任務(wù),需要立即執(zhí)行blcok2中的代碼,但queue是串行隊(duì)列,需要將已經(jīng)取出來(lái)執(zhí)行的block1的代碼執(zhí)行完才能執(zhí)行串行隊(duì)列中的下一個(gè)任務(wù)也就是block2,這樣就互相等待造成死鎖!

結(jié)論:

正在執(zhí)行的代碼是從串行隊(duì)列中取出來(lái)的,而且再次向該串行隊(duì)列中加入同步任務(wù)就會(huì)造成死鎖!兩者缺一不可!

1.如果向該串行隊(duì)列中加入的是異步任務(wù)
2.如果將任務(wù)加入到其他隊(duì)列
3.如果將該串行隊(duì)列改為并發(fā)隊(duì)列這三種情況都不會(huì)產(chǎn)生死鎖!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容