2019-09-27

iOS信号量

信号量的本质:

信号量的本质是数据操作锁, 它本身不具有数据交换的功能,而是通过控制其他的通信资源来实现进程间通信,它本身只是一种外部资源的标识。信号量在此过程中负责数据操作的互斥、同步等功能.

信号量的工作原理

由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:

P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行

V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1.

举个例子,就是 两个进程共享信号量sv,一旦其中一个进程执行了P(sv)操作,它将得到信号量,并可以进入临界区,使sv减1。而第二个进程将被阻止进入临界区,因为 当它试图执行P(sv)时,sv为0,它会被挂起以等待第一个进程离开临界区域并执行V(sv)释放信号量,这时第二个进程就可以恢复执行。

信号量的三个函数是:

dispatch_semaphore_create(long value); // 创建一个semaphore
dispatch_semaphore_signal(dispatch_semaphore_t dsema); // 发送一个信号
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout); // 等到信号

举几个例子,代码如下:

-(void)dispatch_group_function1
{
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_queue_create("com.dispatch.test", DISPATCH_QUEUE_CONCURRENT), ^{
        NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.baidu.com"]];
        NSURLSessionDownloadTask *task = [[NSURLSession sharedSession] downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            // 请求完成,可以通知界面刷新界面等操作
            NSLog(@"第一步网络请求完成");
            // 使信号的信号量+1,这里的信号量本来为0,+1信号量为1(绿灯)
            dispatch_semaphore_signal(semaphore);
        }];
        [task resume];
        // 以下还要进行一些其他的耗时操作
        NSLog(@"耗时操作1继续进行");
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    });
    dispatch_group_async(group, dispatch_queue_create("com.dispatch.test", DISPATCH_QUEUE_CONCURRENT), ^{
        NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.github.com"]];
        NSURLSessionDownloadTask *task = [[NSURLSession sharedSession] downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            // 请求完成,可以通知界面刷新界面等操作
            NSLog(@"第二步网络请求完成");
            // 使信号的信号量+1,这里的信号量本来为0,+1信号量为1(绿灯)
            dispatch_semaphore_signal(semaphore);
        }];
        [task resume];
        // 以下还要进行一些其他的耗时操作
        NSLog(@"耗时操作2继续进行");
        dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"刷新界面等在主线程的操作");
    });
}

首先,默认初始值给的信号量值未0,所以线程1和线程2的执行上其实是没有顺序的,但是,由于在这里设置了dispatch_semaphore_wait,并且当前的信号量值未0,所以会堵塞线程,直到执行了dispatch_semaphore_signal信号量+1,才会继续执行之后的线程操作,打印结果为:

2019-09-27 15:02:51.420389+0800 CPTestDemo[5253:337990] 耗时操作2继续进行
2019-09-27 15:02:51.420414+0800 CPTestDemo[5253:337992] 耗时操作1继续进行
2019-09-27 15:02:51.544547+0800 CPTestDemo[5253:338000] 第一步网络请求完成
2019-09-27 15:02:53.100889+0800 CPTestDemo[5253:337995] 第二步网络请求完成
2019-09-27 15:02:53.101065+0800 CPTestDemo[5253:337950] 刷新界面等在主线程的操作

如果初始值设置dispatch_semaphore_create(1),又会是怎样的结果的

2019-09-27 15:05:34.816451+0800 CPTestDemo[5302:345432] 耗时操作1继续进行
2019-09-27 15:05:34.816451+0800 CPTestDemo[5302:345433] 耗时操作2继续进行
2019-09-27 15:05:34.926754+0800 CPTestDemo[5302:345437] 第一步网络请求完成
2019-09-27 15:05:34.926966+0800 CPTestDemo[5302:345393] 刷新界面等在主线程的操作
2019-09-27 15:05:36.475560+0800 CPTestDemo[5302:345437] 第二步网络请求完成

如果初始值设置dispatch_semaphore_create(2)呢

2019-09-27 15:27:59.737338+0800 CPTestDemo[5587:373223] 耗时操作1继续进行
2019-09-27 15:27:59.737338+0800 CPTestDemo[5587:373222] 耗时操作2继续进行
2019-09-27 15:27:59.758308+0800 CPTestDemo[5587:373190] 刷新界面等在主线程的操作
2019-09-27 15:27:59.880029+0800 CPTestDemo[5587:373220] 第一步网络请求完成
2019-09-27 15:28:01.847547+0800 CPTestDemo[5587:373220] 第二步网络请求完成

因为信号量初始值为2,线程1和2都会执行,由于执行完成信号量减为0,但是组中的任务已经执行完了,所以会接着执行dispatch_group_notify,然后依次是第一步网络请求和第二步网络请求

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 本文用来介绍 iOS 多线程中 GCD 的相关知识以及使用方法。这大概是史上最详细、清晰的关于 GCD 的详细讲...
    花花世界的孤独行者阅读 3,486评论 0 1
  • 1.NSTimer不准时的原因:(1).RunLoop循环处理时间,每次循环是固定时间,只有在这段时间才会去查看N...
    稻春阅读 5,043评论 0 3
  • 锁是一种同步机制,用于多线程环境中对资源访问的限制iOS中常见锁的性能对比图(摘自:ibireme): iOS锁的...
    LiLS阅读 5,431评论 0 6
  • 在iOS开发的道路上,多线程的重要性不言而喻. 大部分我们都停留在基础的使用上面.缺乏高级应用. 缺乏提升,是因为...
    疯狂的木头人阅读 4,862评论 0 1
  • 你们经历了高三,但是它对于你们来说并不是黑色的,只是一种比平时紧张的感觉而已,在内心深处你们还没有真正意义上体会到...
    16aa5fab5f62阅读 1,463评论 0 1

友情链接更多精彩内容