@IT·互联网

GCD我们应该知道些什么

2024-03-11  本文已影响0人  黑炭长

本篇主要记录三个问题
1、GCD面试题分享
2、GCD相关的死锁
3、串行并发底层分析

1、GCD面试题分享

首先我们说一下什么是GCD

dispatch_queue_create("queue.name", DISPATCH_QUEUE_SERIAL);

所有任务按顺序依次执行,结束顺序固定,符合先进先出的基本原则,队列后面的任务必须等待前面的任务执行完毕后才出队列。但是,不要认为串行队列中的所有任务都在同一个线程中执行,串行队列中的异步任务,可能会开启新线程去执行。

dispatch_queue_create("queue.name", DISPATCH_QUEUE_CONCURRENT);

所有任务可以同时执行,结束顺序不固定,只要有可用线程,则队列头部任务将持续出队列。

dispatch_get_main_queue()

本质是一个特殊的串行队列,主队列的任务都在主线程来执行,专门负责调度主线程度的任务,无法开辟新的线程。所以,在主队列下的任务不管是异步任务还是同步任务都不会开辟线程,任务只会在主线程顺序执行。如果在主线程上已经有任务正在执行,主队列会等到主线程空闲后再调度任务。

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

本质是一个特殊的并发队列。在后面加入了“服务质量”和“调度优先级” 两个参数

//串行队列
dispatch_queue_t serial = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
//异步任务
for (int i=0; i<5; i++) {

    dispatch_async(serial, ^{

        NSLog(@"这是第 %d 个任务;线程 %@",i,[NSThread currentThread]);
        if (i==1 || i==3) {
            [NSThread sleepForTimeInterval:2];
        }
    });
}
NSLog(@"=============== 所有任务执行完毕 =====");

执行结果:
2022-05-17 15:27:35.976433+0800 myDemo[278:9179] =============== 所有任务执行完毕 =====
2022-05-17 15:27:35.976538+0800 myDemo[278:9420] 这是第 0 个任务;线程 <NSThread: 0x283628500>{number = 4, name = (null)}
2022-05-17 15:27:35.976655+0800 myDemo[278:9420] 这是第 1 个任务;线程 <NSThread: 0x283628500>{number = 4, name = (null)}
2022-05-17 15:27:37.978072+0800 myDemo[278:9420] 这是第 2 个任务;线程 <NSThread: 0x283628500>{number = 4, name = (null)}
2022-05-17 15:27:37.978150+0800 myDemo[278:9420] 这是第 3 个任务;线程 <NSThread: 0x283628500>{number = 4, name = (null)}
2022-05-17 15:27:39.987439+0800 myDemo[278:9420] 这是第 4 个任务;线程 <NSThread: 0x283628500>{number = 4, name = (null)}

//串行队列
dispatch_queue_t serial = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
//同步任务
for (int i=0; i<5; i++) {

    dispatch_sync(serial, ^{

        NSLog(@"这是第 %d 个任务;线程 %@",i,[NSThread currentThread]);
        if (i==1 || i==3) {
            [NSThread sleepForTimeInterval:2];
        }
    });

执行结果:

2022-05-17 15:14:04.059889+0800 myDemo[252:4951] 这是第 0 个任务;线程 <NSThread: 0x282423f80>{number = 1, name = main}
2022-05-17 15:14:04.059996+0800 myDemo[252:4951] 这是第 1 个任务;线程 <NSThread: 0x282423f80>{number = 1, name = main}
2022-05-17 15:14:06.060559+0800 myDemo[252:4951] 这是第 2 个任务;线程 <NSThread: 0x282423f80>{number = 1, name = main}
2022-05-17 15:14:06.060716+0800 myDemo[252:4951] 这是第 3 个任务;线程 <NSThread: 0x282423f80>{number = 1, name = main}
2022-05-17 15:14:08.061826+0800 myDemo[252:4951] 这是第 4 个任务;线程 <NSThread: 0x282423f80>{number = 1, name = main}
//并发队列
dispatch_queue_t comp = dispatch_queue_create("comp", DISPATCH_QUEUE_CONCURRENT);
//异步任务
for (int i=0; i<5; i++) {

    dispatch_async(comp, ^{

        NSLog(@"这是第 %d 个任务;线程 %@",i,[NSThread currentThread]);
        if (i==1 || i==3) {
            [NSThread sleepForTimeInterval:2];
        }
    });
}
NSLog(@"=============== 所有任务执行完毕 =====");

执行结果:
2022-05-17 15:39:06.309859+0800 myDemo[294:11951] =============== 所有任务执行完毕 =====
2022-05-17 15:39:06.309962+0800 myDemo[294:12131] 这是第 0 个任务;线程 <NSThread: 0x281719380>{number = 5, name = (null)}
2022-05-17 15:39:06.310064+0800 myDemo[294:12131] 这是第 1 个任务;线程 <NSThread: 0x281719380>{number = 5, name = (null)}
2022-05-17 15:39:06.310165+0800 myDemo[294:12134] 这是第 2 个任务;线程 <NSThread: 0x2817d2300>{number = 4, name = (null)}
2022-05-17 15:39:06.310236+0800 myDemo[294:12134] 这是第 3 个任务;线程 <NSThread: 0x2817d2300>{number = 4, name = (null)}
2022-05-17 15:39:06.311765+0800 myDemo[294:12130] 这是第 4 个任务;线程 <NSThread: 0x281719d40>{number = 6, name = (null)}

//并发队列
dispatch_queue_t comp = dispatch_queue_create("comp", DISPATCH_QUEUE_CONCURRENT);
//同步任务
for (int i=0; i<5; i++) {

    dispatch_sync(comp, ^{

        NSLog(@"这是第 %d 个任务;线程 %@",i,[NSThread currentThread]);
        if (i==1 || i==3) {
            [NSThread sleepForTimeInterval:2];
        }
    });
}
NSLog(@"=============== 所有任务执行完毕 =====");

执行结果:
2022-05-17 15:37:08.804872+0800 myDemo[287:11040] 这是第 0 个任务;线程 <NSThread: 0x282b3fac0>{number = 1, name = main}
2022-05-17 15:37:08.804962+0800 myDemo[287:11040] 这是第 1 个任务;线程 <NSThread: 0x282b3fac0>{number = 1, name = main}
2022-05-17 15:37:10.805818+0800 myDemo[287:11040] 这是第 2 个任务;线程 <NSThread: 0x282b3fac0>{number = 1, name = main}
2022-05-17 15:37:10.806122+0800 myDemo[287:11040] 这是第 3 个任务;线程 <NSThread: 0x282b3fac0>{number = 1, name = main}
2022-05-17 15:37:12.807415+0800 myDemo[287:11040] 这是第 4 个任务;线程 <NSThread: 0x282b3fac0>{number = 1, name = main}
2022-05-17 15:37:12.807771+0800 myDemo[287:11040] =============== 所有任务执行完毕 =====
//同步任务+主线程 == 相互等待,死锁
for (int i=0; i<5; i++) {

        dispatch_sync(dispatch_get_main_queue(), ^{

        NSLog(@"这是第 %d 个任务;线程 %@",i,[NSThread currentThread]);
        if (i==1 || i==3) {
            [NSThread sleepForTimeInterval:2];
        }
    });
}
- (void)gcdasy {
    
//    dispatch_queue_t queue = dispatch_queue_create("yiqijiaoyu", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue = dispatch_queue_create("yiqijiaoyu", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        NSLog(@"1");
    });
    dispatch_async(queue, ^{
        NSLog(@"2");
        dispatch_async(queue, ^{
            NSLog(@"3");
        });
        NSLog(@"4");
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"5");
    });
    
    /// 15234 - 15243,
}
- (void)gcdsy {
    NSLog(@"1");
    dispatch_queue_t queue = dispatch_queue_create("yiqijiaoyu", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"2");
    });
    NSLog(@"3");
    dispatch_sync(queue, ^{
        NSLog(@"4");
    });
    
    /// 1324
}
- (void)test6 {
    
    __block NSInteger a = 0;
    while (a < 10) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            a ++;
            NSLog(@"%ld: %@", a, [NSThread currentThread]);
        });
    }
    
    NSLog(@"=========%ld", a);
    /// a的值不确定 但是肯定大于等于10,a打印的次数不确定,可能很大
}

2、GCD相关的死锁

- (void)gcdasy {
    
    dispatch_queue_t queue = dispatch_queue_create("yiqijiaoyu", DISPATCH_QUEUE_SERIAL);
//    dispatch_queue_t queue = dispatch_queue_create("yiqijiaoyu", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        NSLog(@"1");
    });
    dispatch_async(queue, ^{
        NSLog(@"2");
        dispatch_sync(queue, ^{// 死锁
            NSLog(@"3");
        });
        NSLog(@"4");
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"5");
    });
    
    
}
//同步任务+主线程 == 相互等待,死锁
for (int i=0; i<5; i++) {

        dispatch_sync(dispatch_get_main_queue(), ^{

        NSLog(@"这是第 %d 个任务;线程 %@",i,[NSThread currentThread]);
        if (i==1 || i==3) {
            [NSThread sleepForTimeInterval:2];
        }
    });
}

3、串行并发底层分析

打开libDispatch源码

串行的标志性代码是 DQF_WIDTH(1)

初始化的时候会判断串行并发标志位去限制width是多少,串行指定是1,并发是14


image.png

来看看_dispatch_queue_init的队列初始化,我们关注的队列是串行和并发的根本区别就是DQF_WIDTH(width),串行是DQF_WIDTH(1)

上一篇 下一篇

猜你喜欢

热点阅读