iOS 多线程 GCD(二)

2019-04-08  本文已影响0人  ivylee_mr

前言

本文主要接扫GCD的信号量相关的内容。

代码的下载地址demo;

1、信号量简介

此处省略一万字......

2、信号量的三个主要方法(函数)说明

dispatch_semaphore_create(long value);
方法作用:创建信号总量,即初始信号量允许的最大值,例如
dispatch_semaphore_t sem = dispatch_semaphore_create(0);
参数:信号总量的初值,数据类型为long类型。
返回值:如果value小于0,创建的sem对象其实是NULL类型。

dispatch_semaphore_signal(dispatch_semaphore_t deem);
方法作用:发送信号量 ,例如
dispatch_semaphore_signal(sem);
参数: dispatch_semaphore_t对象,比如刚才创建的sem
返回值:返回值为long类型。
当返回值为0时,表示当前并没有线程等待其处理的信号量,其处理的信号总量增加1
当返回值不为0时,表示其当前有一个或者多个线程等待其处理的信号量,并且该函数唤醒了一个等待的线程(当线程有优先级的时候,唤醒优先级最高的线程,否则随机唤醒)

dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
方法作用: 等待信号量,例如
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
参数: dispatch_semaphore_t对象和 超时时间类型DISPATCH_TIME_FOREVERDISPATCH_TIME_NOW。目前一般都是选择DISPATCH_TIME_FOREVER
DISPATCH_TIME_FOREVERDISPATCH_TIME_NOW具体区别如下:

  • DISPATCH_TIME_FOREVER 超时时间为永远,表示会一直等待信号量为正数,才会继续运行
  • DISPATCH_TIME_NOW 超时时间为0,表示忽略信号量,直接运行。

3、如何使用信号量?

下面我们看下如下代码,分别设置信号量semValue01234时的不同信号量初始值的打印结果

- (void)semaphoreTestMethodWithSemValue:(long)semValue{
    NSLog(@"\n\n\n\n");
    NSLog(@"semaphoreTestMethod 总任务开启");
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(semValue);
    dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //任务1
    dispatch_async(quene, ^{
        NSLog(@"任务一开始");
        NSInteger currentSem = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"任务一 currentSem = %ld:当前线程:%@",currentSem ,[NSThread currentThread]);
        
        [self netWorkingComletionHandler:^(NSString *status) {
            NSLog(@"任务一 任务Block回掉完成 %@",status);
        }];
        
        NSLog(@"完成任务一 currentSem = %ld:当前线程:%@",currentSem ,[NSThread currentThread]);
        dispatch_semaphore_signal(semaphore);
    });
    //任务2
    dispatch_async(quene, ^{
        NSLog(@"任务二开始");
        NSInteger currentSem = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"任务二 currentSem = %ld:当前线程:%@",currentSem ,[NSThread currentThread]);
        [self netWorkingComletionHandler:^(NSString *status) {
            NSLog(@"任务二 任务Block回掉完成 %@",status);
        }];
        NSLog(@"完成任务二 currentSem = %ld:当前线程:%@",currentSem ,[NSThread currentThread]);
        dispatch_semaphore_signal(semaphore);
    });
    //任务3
    dispatch_async(quene, ^{
        NSLog(@"任务三开始");
        NSInteger currentSem = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"任务三 currentSem = %ld:当前线程:%@",currentSem ,[NSThread currentThread]);
        [self netWorkingComletionHandler:^(NSString *status) {
            NSLog(@"任务三 任务Block回掉完成 %@",status);
        }];
        NSLog(@"完成任务三 currentSem = %ld:当前线程:%@",currentSem ,[NSThread currentThread]);
        dispatch_semaphore_signal(semaphore);
    });
    
    NSLog(@"semaphoreTestMethod 总任务关闭");
}

semValue = 0 打印结果

2019-04-03 17:15:32.008373+0800 GCDDemo[4793:333586] 
2019-04-03 17:15:32.008519+0800 GCDDemo[4793:333586] semaphoreTestMethod 总任务开启
2019-04-03 17:15:32.008647+0800 GCDDemo[4793:333586] semaphoreTestMethod 总任务关闭
2019-04-03 17:15:32.008695+0800 GCDDemo[4793:333639] 任务一开始
2019-04-03 17:15:32.008707+0800 GCDDemo[4793:333637] 任务二开始
2019-04-03 17:15:32.008750+0800 GCDDemo[4793:333811] 任务三开始

semValue = 1 打印结果

2019-04-03 17:22:05.810571+0800 GCDDemo[4793:333586] semaphoreTestMethod 总任务开启
2019-04-03 17:22:05.810803+0800 GCDDemo[4793:333586] semaphoreTestMethod 总任务关闭
2019-04-03 17:22:05.810834+0800 GCDDemo[4793:333812] 任务一开始
2019-04-03 17:22:05.810948+0800 GCDDemo[4793:340419] 任务二开始
2019-04-03 17:22:05.810978+0800 GCDDemo[4793:340420] 任务三开始
2019-04-03 17:22:05.811148+0800 GCDDemo[4793:333812] 任务一 currentSem = 0:当前线程:<NSThread: 0x600002e8c080>{number = 3, name = (null)}
2019-04-03 17:22:05.811356+0800 GCDDemo[4793:333812] 完成任务一 currentSem = 0:当前线程:<NSThread: 0x600002e8c080>{number = 3, name = (null)}
2019-04-03 17:22:05.811557+0800 GCDDemo[4793:340419] 任务二 currentSem = 0:当前线程:<NSThread: 0x600002e8c480>{number = 5, name = (null)}
2019-04-03 17:22:05.811721+0800 GCDDemo[4793:340419] 完成任务二 currentSem = 0:当前线程:<NSThread: 0x600002e8c480>{number = 5, name = (null)}
2019-04-03 17:22:05.812068+0800 GCDDemo[4793:340420] 任务三 currentSem = 0:当前线程:<NSThread: 0x600002ee43c0>{number = 6, name = (null)}
2019-04-03 17:22:05.812324+0800 GCDDemo[4793:340420] 完成任务三 currentSem = 0:当前线程:<NSThread: 0x600002ee43c0>{number = 6, name = (null)}
2019-04-03 17:22:07.815793+0800 GCDDemo[4793:333586] 任务一 任务Block回掉完成 当前线程是:<NSThread: 0x600002e8c500>{number = 4, name = (null)} 随机等待:2秒
2019-04-03 17:22:07.816064+0800 GCDDemo[4793:333586] 任务三 任务Block回掉完成 当前线程是:<NSThread: 0x600002e8c480>{number = 5, name = (null)} 随机等待:2秒
2019-04-03 17:22:10.815416+0800 GCDDemo[4793:333586] 任务二 任务Block回掉完成 当前线程是:<NSThread: 0x600002e8c080>{number = 3, name = (null)} 随机等待:5秒

semValue = 2 打印结果

2019-04-03 17:27:24.062999+0800 GCDDemo[4793:333586] semaphoreTestMethod 总任务开启
2019-04-03 17:27:24.063133+0800 GCDDemo[4793:333586] semaphoreTestMethod 总任务关闭
2019-04-03 17:27:24.063176+0800 GCDDemo[4793:333812] 任务一开始
2019-04-03 17:27:24.063244+0800 GCDDemo[4793:345396] 任务二开始
2019-04-03 17:27:24.063274+0800 GCDDemo[4793:345397] 任务三开始
2019-04-03 17:27:24.063346+0800 GCDDemo[4793:333812] 任务一 currentSem = 0:当前线程:<NSThread: 0x600002e8c080>{number = 3, name = (null)}
2019-04-03 17:27:24.063426+0800 GCDDemo[4793:345396] 任务二 currentSem = 0:当前线程:<NSThread: 0x600002e04580>{number = 7, name = (null)}
2019-04-03 17:27:24.063519+0800 GCDDemo[4793:333812] 完成任务一 currentSem = 0:当前线程:<NSThread: 0x600002e8c080>{number = 3, name = (null)}
2019-04-03 17:27:24.063587+0800 GCDDemo[4793:345396] 完成任务二 currentSem = 0:当前线程:<NSThread: 0x600002e04580>{number = 7, name = (null)}
2019-04-03 17:27:24.063746+0800 GCDDemo[4793:345397] 任务三 currentSem = 0:当前线程:<NSThread: 0x600002e04500>{number = 10, name = (null)}
2019-04-03 17:27:24.064110+0800 GCDDemo[4793:345397] 完成任务三 currentSem = 0:当前线程:<NSThread: 0x600002e04500>{number = 10, name = (null)}
2019-04-03 17:27:25.065614+0800 GCDDemo[4793:333586] 任务三 任务Block回掉完成 当前线程是:<NSThread: 0x600002e04580>{number = 7, name = (null)} 随机等待:1秒
2019-04-03 17:27:28.067425+0800 GCDDemo[4793:333586] 任务一 任务Block回掉完成 当前线程是:<NSThread: 0x600002e8c000>{number = 8, name = (null)} 随机等待:4秒
2019-04-03 17:27:28.067670+0800 GCDDemo[4793:333586] 任务二 任务Block回掉完成 当前线程是:<NSThread: 0x600002e8a400>{number = 9, name = (null)} 随机等待:4秒

semValue = 3semValue = 4semValue = 2基本类似


通过以上的打印结果,我们可以知道:

3、信号量+并发Block回掉

如果我们将信号量结合到回掉中会是如何呢?

#pragma mark - 信号量 + 回掉
- (void)semaphoreBlockTestMethodWithSemValue:(long)semValue{
    NSLog(@"\n\n\n\n");
    NSLog(@"semaphoreTestMethod 总任务开启");
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(semValue);
    dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    //任务1
    dispatch_async(quene, ^{
        NSLog(@"任务一开始");
        NSInteger currentSem = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"任务一 currentSem = %ld:当前线程:%@",currentSem ,[NSThread currentThread]);
        
        [self netWorkingComletionHandler:^(NSString *status) {
            NSLog(@"任务一 任务Block回掉完成 %@",status);
            dispatch_semaphore_signal(semaphore);
        }];
        
        NSLog(@"完成任务一 currentSem = %ld:当前线程:%@",currentSem ,[NSThread currentThread]);
    });
    //任务2
    dispatch_async(quene, ^{
        NSLog(@"任务二开始");
        NSInteger currentSem = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"任务二 currentSem = %ld:当前线程:%@",currentSem ,[NSThread currentThread]);
        [self netWorkingComletionHandler:^(NSString *status) {
            NSLog(@"任务二 任务Block回掉完成 %@",status);
            dispatch_semaphore_signal(semaphore);
        }];
        NSLog(@"完成任务二 currentSem = %ld:当前线程:%@",currentSem ,[NSThread currentThread]);
    });
    //任务3
    dispatch_async(quene, ^{
        NSLog(@"任务三开始");
        NSInteger currentSem = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"任务三 currentSem = %ld:当前线程:%@",currentSem ,[NSThread currentThread]);
        [self netWorkingComletionHandler:^(NSString *status) {
            NSLog(@"任务三 任务Block回掉完成 %@",status);
            dispatch_semaphore_signal(semaphore);
        }];
        NSLog(@"完成任务三 currentSem = %ld:当前线程:%@",currentSem ,[NSThread currentThread]);
    });
    
    NSLog(@"semaphoreTestMethod 总任务关闭");
}

比如我们设置信号量的初始值为2,如下是打印结果

2019-04-03 18:09:59.097874+0800 GCDDemo[5095:376935] semaphoreTestMethod 总任务开启
2019-04-03 18:09:59.098011+0800 GCDDemo[5095:376935] semaphoreTestMethod 总任务关闭
2019-04-03 18:09:59.098036+0800 GCDDemo[5095:377194] 任务一开始
2019-04-03 18:09:59.098109+0800 GCDDemo[5095:390359] 任务二开始
2019-04-03 18:09:59.098139+0800 GCDDemo[5095:390360] 任务三开始
2019-04-03 18:09:59.098184+0800 GCDDemo[5095:377194] 任务一 currentSem = 0:当前线程:<NSThread: 0x6000025bad00>{number = 6, name = (null)}
2019-04-03 18:09:59.098282+0800 GCDDemo[5095:390359] 任务二 currentSem = 0:当前线程:<NSThread: 0x600002560240>{number = 7, name = (null)}
2019-04-03 18:09:59.098359+0800 GCDDemo[5095:377194] 完成任务一 currentSem = 0:当前线程:<NSThread: 0x6000025bad00>{number = 6, name = (null)}
2019-04-03 18:09:59.098444+0800 GCDDemo[5095:390359] 完成任务二 currentSem = 0:当前线程:<NSThread: 0x600002560240>{number = 7, name = (null)}
2019-04-03 18:10:01.100229+0800 GCDDemo[5095:376935] 任务一 任务Block回掉完成 当前线程是:<NSThread: 0x600002560680>{number = 8, name = (null)} 随机等待:2秒
2019-04-03 18:10:01.100646+0800 GCDDemo[5095:390360] 任务三 currentSem = 0:当前线程:<NSThread: 0x600002598880>{number = 10, name = (null)}
2019-04-03 18:10:01.100859+0800 GCDDemo[5095:390360] 完成任务三 currentSem = 0:当前线程:<NSThread: 0x600002598880>{number = 10, name = (null)}
2019-04-03 18:10:02.101269+0800 GCDDemo[5095:376935] 任务二 任务Block回掉完成 当前线程是:<NSThread: 0x60000257ce40>{number = 9, name = (null)} 随机等待:3秒
2019-04-03 18:10:06.103983+0800 GCDDemo[5095:376935] 任务三 任务Block回掉完成 当前线程是:<NSThread: 0x600002560680>{number = 8, name = (null)} 随机等待:5秒

4、实现异步多线程并发任务的同步操作

#pragma mark - 实现异步多线程并发任务的同步操作
- (void)semaphoreAsyncGlobalTask{
    NSLog(@"\n\n\n\n");
    NSLog(@"semaphoreAsyncGlobalTask 总任务开启");
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    NSLog(@"任务执行 -> 开始线程:%@",[NSThread currentThread]);      // 打印当前线程
    dispatch_async(quene, ^{
        [NSThread sleepForTimeInterval:2];              // 模拟耗时操作
        NSLog(@"任务执行 一  -> 结束 线程:%@",[NSThread currentThread]);      // 打印当前线程
        dispatch_semaphore_signal(semaphore);
    });
    NSLog(@"任务执行 二 -> 结束  线程:%@",[NSThread currentThread]);      // 打印当前线程
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    NSLog(@"任务执行 三 -> 结束  线程:%@",[NSThread currentThread]);      // 打印当前线程
    NSLog(@"semaphoreAsyncGlobalTask 总任务关闭");
}

打印结果

2019-04-04 11:47:12.788469+0800 GCDDemo[1713:126301] 任务执行 -> 开始线程:<NSThread: 0x600002c01440>{number = 1, name = main}
2019-04-04 11:47:12.788753+0800 GCDDemo[1713:126301] 任务执行 二 -> 结束  线程:<NSThread: 0x600002c01440>{number = 1, name = main}
2019-04-04 11:47:14.790166+0800 GCDDemo[1713:126762] 任务执行 一  -> 结束 线程:<NSThread: 0x600002c906c0>{number = 3, name = (null)}
2019-04-04 11:47:14.790478+0800 GCDDemo[1713:126301] 任务执行 三 -> 结束  线程:<NSThread: 0x600002c01440>{number = 1, name = main}
2019-04-04 11:47:14.790608+0800 GCDDemo[1713:126301] semaphoreAsyncGlobalTask 总任务关闭

我们再来看下面一段代码

#pragma mark - 实现异步多线程并发带Block回掉任务的同步操作
- (void)semaphoreAsyncGlobalBlockTask{
    NSLog(@"\n\n\n\n");
    NSLog(@"semaphoreAsyncGlobalBlockTask 总任务开启");
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    NSLog(@"任务执行 -> 开始线程:%@",[NSThread currentThread]);      // 打印当前线程
    dispatch_async(quene, ^{
        NSLog(@"Block任务执行 -> 开始线程:%@",[NSThread currentThread]);      // 打印当前线程
        [self netWorkingComletionHandler:^(NSString *status) {
            NSLog(@"Block任务执行 一  -> 结束 线程:%@",[NSThread currentThread]);      // 打印当前线程
            dispatch_semaphore_signal(semaphore);
        }];
    });
    NSLog(@"任务执行 二 -> 结束  线程:%@",[NSThread currentThread]);      // 打印当前线程
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    NSLog(@"任务执行 三 -> 结束  线程:%@",[NSThread currentThread]);      // 打印当前线程
    NSLog(@"semaphoreAsyncGlobalBlockTask 总任务关闭");
}

再看看其打印结果

2019-04-08 09:05:26.758092+0800 GCDDemo[1372:29281] 
2019-04-08 09:05:26.758280+0800 GCDDemo[1372:29281] semaphoreAsyncGlobalBlockTask 总任务开启
2019-04-08 09:05:26.758490+0800 GCDDemo[1372:29281] 任务执行 -> 开始线程:<NSThread: 0x600002abe940>{number = 1, name = main}
2019-04-08 09:05:26.758779+0800 GCDDemo[1372:29281] 任务执行 二 -> 结束  线程:<NSThread: 0x600002abe940>{number = 1, name = main}
2019-04-08 09:05:26.758780+0800 GCDDemo[1372:29342] Block任务执行 -> 开始线程:<NSThread: 0x600002aca280>{number = 3, name = (null)}
上一篇下一篇

猜你喜欢

热点阅读