iOS GCD的一些用法

iOS GCD的一些用法

多线程GCD是纯C的API, 使用起来更高效

本文主要讲了
1 GCD异步操作
2 GCD经典死锁
3 GCD线程组
4 GCD信号量

1 异步并发

- (void)diapatchAsyncWithConcurrent {
    dispatch_queue_t queue = dispatch_queue_create("com.nyl", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2]; // 线程睡眠2秒, 模拟耗时操作
            NSLog(@"1 -- %@", [NSThread currentThread]);
        }
    });
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; i++) {
            [NSThread sleepForTimeInterval:2]; // 线程睡眠2秒, 模拟耗时操作
            NSLog(@"2 -- %@", [NSThread currentThread]);
        }
    });
    /*
     2019-08-10 21:36:03.838942+0800 iOSAdvancedLearningDemo[2901:423038] 1 -- <NSThread: 0x600000590500>{number = 4, name = (null)}
     2019-08-10 21:36:03.838955+0800 iOSAdvancedLearningDemo[2901:423041] 2 -- <NSThread: 0x600000549680>{number = 3, name = (null)}
     2019-08-10 21:36:05.843703+0800 iOSAdvancedLearningDemo[2901:423041] 2 -- <NSThread: 0x600000549680>{number = 3, name = (null)}
     2019-08-10 21:36:05.843703+0800 iOSAdvancedLearningDemo[2901:423038] 1 -- <NSThread: 0x600000590500>{number = 4, name = (null)}
     */
    // 开启了两个子线程
}

2 经典死锁

- (void)testDeadlock {
    NSLog(@"test1");
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"test2");
    });
    NSLog(@"test3");
}

以上代码只能打印test1, 发生了死锁;
原因: testDeadlock是在同步操作队列里面的, 其内部也有dispatch_sync操作, 两个操作相互等待, 发生死锁


3 线程组

线程组用来执行n个异步操作,等n个异步操作完成后,才进行回调;
线程组有两种写法,作用相同:
第1种:dispatch_group_async
第2种:dispatch_group_enter & dispatch_group_leave组合

第一种流程:
创建dispatch_group_create -->
执行异步操作dispatch_group_async -->
线程等待dispatch_group_wait(上面异步操作未完成会阻塞下面的代码) 或者 dispatch_group_notify(不会阻塞下面的代码)

第一种流程代码演示

- (void)dispatchGroupWait {
    dispatch_group_t dispatchGroup = dispatch_group_create();
    
    dispatch_group_async(dispatchGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [NSThread sleepForTimeInterval:4]; // 线程睡眠
        NSLog(@"1. 第1个网络请求成功");
    });
    
    dispatch_group_async(dispatchGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [NSThread sleepForTimeInterval:1]; // 线程睡眠
        NSLog(@"2. 第2个网络请求成功");
    });
    
    // dispatch_group_wait 等待上面的任务全部执行完毕, 会继续向下执行(线程阻塞)
    dispatch_group_wait(dispatchGroup, DISPATCH_TIME_FOREVER);/** 第1个参数线程组, 第2个参数超时时间(DISPATCH_TIME_FOREVER永不超时) */
    
    NSLog(@"全部执行成功");
    /*
     2019-08-10 22:34:15.997349+0800 iOSAdvancedLearningDemo[3472:474544] 2. 第2个网络请求成功
     2019-08-10 22:34:18.995982+0800 iOSAdvancedLearningDemo[3472:474410] 1. 第1个网络请求成功
     2019-08-10 22:34:20.997333+0800 iOSAdvancedLearningDemo[3472:474275] 全部执行成功
     */
}

第2种流程:
创建dispatch_group_create -->
执行异步操作dispatch_group_enter 和dispatch_group_leave组合使用 -->
线程等待dispatch_group_wait(上面异步操作未完成会阻塞下面的代码) 或者 dispatch_group_notify(不会阻塞下面的代码)

第2种流程代码演示

- (void)dispatchGroupEnterAndLeave {
    
    dispatch_group_t dispatchGroup = dispatch_group_create();
    
    dispatch_group_enter(dispatchGroup);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [NSThread sleepForTimeInterval:4]; // 线程睡眠
        NSLog(@"1. 第1个网络请求成功");
        dispatch_group_leave(dispatchGroup);
    });
    
    dispatch_group_enter(dispatchGroup);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [NSThread sleepForTimeInterval:1]; // 线程睡眠
        NSLog(@"2. 第2个网络请求成功");
        dispatch_group_leave(dispatchGroup);
    });
    
    dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
        NSLog(@"完成上面所有网络请求, 回到了主线程");
    });
    
    NSLog(@"dispatch_group_notify 不会阻塞我, 我可以立即执行");
    
    /*
     2019-08-12 10:16:15.689168+0800 iOSAdvancedLearningDemo[2348:38998] dispatch_group_notify 不会阻塞我, 我可以立即执行
     2019-08-12 10:16:16.693262+0800 iOSAdvancedLearningDemo[2348:39033] 2. 第2个网络请求成功
     2019-08-12 10:16:19.692010+0800 iOSAdvancedLearningDemo[2348:39032] 1. 第1个网络请求成功
     2019-08-12 10:16:19.692376+0800 iOSAdvancedLearningDemo[2348:38998] 完成上面所有网络请求, 回到了主线程
     */   
}

小结:
从dispatch_group_enter, dispatch_group_leave运行结果看出, 当所有任务完成之后, 才执行dispatch_group_notify中的任务. 这一点等同于dispatch_group_async。

调用了dispatch_group_enter, 必须有与之对应的dispatch_group_leave才行(跟引用计数类似), 如果缺少不是成对出现, 有可能造成内存泄露或者无法进入到dispatch_group_notify函数.

如果注释了其中的dispatch_group_enter(dispatchGroup), 会造成内存泄露, 如果注释了其中的一个dispatch_group_leave(dispatchGroup)则永远无法进入dispatch_group_notify函数。


4 信号量

dispatch_semaphore_create创建一个信号量, 初始化0(必须>=0, 否则该方法返回NULL)
dispatch_semaphore_wait: 当dsema为0的时候,dispatch_semaphore_wait下面的语句不会执行, 当dsema>0的时候, 下面的语句才会执行, 并且使dsema减去1;
dispatch_semaphore_signal: 发送一个信号量使dsema加1

重要提示:

dispatch_semaphore_signal必须与dispatch_semaphore_wait调用次数保持一致, 否则有可能造成EXC_BAD_INSTRUCTION(程序异常崩溃)

信号量可用于线程同步
example

- (void)dispatchSemaphoreSync {
    NSLog(@"semaphore---begin");
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    __block int num = 0;
    dispatch_async(queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"1---%@",[NSThread currentThread]);
        num = 200;
        dispatch_semaphore_signal(semaphore);
    });
    
    // 等待上面的异步操作执行完毕, 才会执行下面的NSLog代码
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    NSLog(@"end,number = %d", num);
}
 2019-08-11 00:37:46.169351+0800 iOSAdvancedLearningDemo[4570:570595] semaphore---begin
 2019-08-11 00:37:48.173772+0800 iOSAdvancedLearningDemo[4570:570637] 1---<NSThread: 0x600003875a40>{number = 3, name = (null)}
 2019-08-11 00:37:48.174012+0800 iOSAdvancedLearningDemo[4570:570595] end,num = 200
 以上先执行num=200, 才会进入到NSLog语句;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值