美文网首页iOS开发iOS面试iOS Developer
iOS for循环请求网络时,使用信号量导致死锁

iOS for循环请求网络时,使用信号量导致死锁

作者: BlackStar暗星 | 来源:发表于2019-10-11 15:32 被阅读0次

有的时候我们会遇到这样的需求:
循环请求网络,但是在循环的过程中,必须上一个网络回调完成后才能请求下一个网络即进行下一个循环,也就是所谓的多个异步网络做同步请求,首先想到的就是用信号量拦截,如:

-(void)semaphoreTest{
    
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
   for (int i = 0; i<10; i++) {
        [self semaphoreTestBlock:^(NSString *TNT) {
            NSLog(@"任务完成 %d",i);
            dispatch_semaphore_signal(semaphore);
        }];
        
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"信号量限制 %d",i);
    }
}

//这里用延迟模拟异步网络请求
-(void)semaphoreTestBlock:(void(^)(NSString * TNT))block{
    /*
      queue 的类型无论是串行队列还是并行队列并不影响最终结果
       如果 queue = dispatch_get_main_queue() 将会堵塞组线程,造成死锁
    */
    dispatch_queue_t queue = dispatch_queue_create("myqueue",DISPATCH_QUEUE_SERIAL);
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), queue, ^{
        block(@"完成");
    });
}

这段代码的输出结果为:

2019-10-11 14:40:23.961328+0800 LJC[9013:1358198] 任务完成 0
2019-10-11 14:40:23.961751+0800 LJC[9013:1356826] 信号量限制 0
2019-10-11 14:40:25.061312+0800 LJC[9013:1358198] 任务完成 1
2019-10-11 14:40:25.061673+0800 LJC[9013:1356826] 信号量限制 1
2019-10-11 14:40:26.062082+0800 LJC[9013:1356931] 任务完成 2
2019-10-11 14:40:26.062381+0800 LJC[9013:1356826] 信号量限制 2
2019-10-11 14:40:27.062883+0800 LJC[9013:1356931] 任务完成 3
2019-10-11 14:40:27.063275+0800 LJC[9013:1356826] 信号量限制 3
2019-10-11 14:40:28.160535+0800 LJC[9013:1356931] 任务完成 4
2019-10-11 14:40:28.160988+0800 LJC[9013:1356826] 信号量限制 4
2019-10-11 14:40:29.161327+0800 LJC[9013:1356931] 任务完成 5
2019-10-11 14:40:29.161512+0800 LJC[9013:1356826] 信号量限制 5
2019-10-11 14:40:30.161756+0800 LJC[9013:1356931] 任务完成 6
2019-10-11 14:40:30.161989+0800 LJC[9013:1356826] 信号量限制 6
2019-10-11 14:40:31.261507+0800 LJC[9013:1356931] 任务完成 7
2019-10-11 14:40:31.261912+0800 LJC[9013:1356826] 信号量限制 7
2019-10-11 14:40:32.361503+0800 LJC[9013:1356931] 任务完成 8
2019-10-11 14:40:32.361870+0800 LJC[9013:1356826] 信号量限制 8
2019-10-11 14:40:33.461544+0800 LJC[9013:1358198] 任务完成 9
2019-10-11 14:40:33.461953+0800 LJC[9013:1356826] 信号量限制 9

如果我们把
dispatch_queue_t queue = dispatch_queue_create("myqueue",DISPATCH_QUEUE_SERIAL);
替换成
dispatch_queue_t queue = dispatch_get_main_queue()
发现输出结果为空

为什么呢?
首先我们要知道
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
他怎么才能实现锁的功能,他的锁其实是针对线程的,我们当前任务是在主线程执行的,我们就需要在主线程上锁。
完成任务我们去将信号量+1,即执行
dispatch_semaphore_signal(semaphore)
这个时候发现你的回调也是在主线程触发的,但是此时主线程上锁,已经卡住了,是不能让你在主线程做任务的,这就形成了相互等待,卡死了,所以我们需要将回调任务放在非主线程中(以目前这个例子来说,就是非主线程,其实我们最终调整的目的是让执行任务和回调任务不在同一线程即可)。

那我们如果将任务(for循环)在子线程中执行,回调在主线程中是否可以呢?下面我们修改代码

-(void)semaphoreTest{
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
           
           for (int i = 0; i<10; i++) {
               [self semaphoreTestBlock:^(NSString *TNT) {
                   NSLog(@"任务完成 %d",i);
                   dispatch_semaphore_signal(semaphore);
               }];
               
               dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
               NSLog(@"信号量限制 %d",i);
           }
    });
}

-(void)semaphoreTestBlock:(void(^)(NSString * TNT))block{
    
//    dispatch_queue_t queue = dispatch_queue_create("myqueue",DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), queue, ^{
        block(@"完成");
    });
}

输出结果

2019-10-11 14:51:00.224109+0800 LJC[9063:1362953] 任务完成 0
2019-10-11 14:51:00.224486+0800 LJC[9063:1363099] 信号量限制 0
2019-10-11 14:51:01.325117+0800 LJC[9063:1362953] 任务完成 1
2019-10-11 14:51:01.325493+0800 LJC[9063:1363099] 信号量限制 1
2019-10-11 14:51:02.425129+0800 LJC[9063:1362953] 任务完成 2
2019-10-11 14:51:02.425491+0800 LJC[9063:1363099] 信号量限制 2
2019-10-11 14:51:03.524266+0800 LJC[9063:1362953] 任务完成 3
2019-10-11 14:51:03.524715+0800 LJC[9063:1363099] 信号量限制 3
2019-10-11 14:51:04.625254+0800 LJC[9063:1362953] 任务完成 4
2019-10-11 14:51:04.625659+0800 LJC[9063:1363099] 信号量限制 4
2019-10-11 14:51:05.725228+0800 LJC[9063:1362953] 任务完成 5
2019-10-11 14:51:05.725573+0800 LJC[9063:1363099] 信号量限制 5
2019-10-11 14:51:06.726094+0800 LJC[9063:1362953] 任务完成 6
2019-10-11 14:51:06.726442+0800 LJC[9063:1363099] 信号量限制 6
2019-10-11 14:51:07.825270+0800 LJC[9063:1362953] 任务完成 7
2019-10-11 14:51:07.825613+0800 LJC[9063:1363099] 信号量限制 7
2019-10-11 14:51:08.925323+0800 LJC[9063:1362953] 任务完成 8
2019-10-11 14:51:08.925674+0800 LJC[9063:1363099] 信号量限制 8
2019-10-11 14:51:10.025359+0800 LJC[9063:1362953] 任务完成 9
2019-10-11 14:51:10.025722+0800 LJC[9063:1363099] 信号量限制 9

这就验证了我们的想法, 执行任务和任务回调是不能在一个线程中的

整理

在使用信号量的时候,需要注意 dispatch_semaphore_wait 需要和 任务 放在同一线程,在任务执行异步回调的时候,需要将回调放在与执行任务不同的线程中,因为如果在同一线程中 dispatch_semaphore_wait 操作会造成相互等待导致死锁问题,我们在使用 AFNetWorking 的时候,他默认的回调是在 主线程中,所以我们在配合 AFNetWorking 使用信号量的时候可以指定 AFNetWorking 的回调线程,或者我们在执行任务的时候,将任务放在其他线程

注释:
写这篇文章是因为我在用信号量配合AFNetWorking做网路任务的时候发现一只卡死,在网上找的都说指定AFNetWorking 的 completionQueue ,然后我更改了代码,request是我们网络对AFNetWorking的封装对象实例,按理来说是没问题的,但是不知道为什么还是会造成死锁。目前原因没找到。所以我将for循环再放了子线程中

request.sessionManager.completionQueue = dispatch_get_global_queue(0, 0);

如发现理解错误,望指出 ^_^ THANKS

相关文章

  • iOS for循环请求网络时,使用信号量导致死锁

    有的时候我们会遇到这样的需求:循环请求网络,但是在循环的过程中,必须上一个网络回调完成后才能请求下一个网络即进行下...

  • iOS网络请求相关框架的使用

    iOS网络请求相关框架的使用 iOS网络请求相关框架的使用

  • 信号量

    1、在afnetworking中使用信号量时,造成死锁 AFURLSessionManager 所有回调都会放到主...

  • 爬虫反复请求网络单元

    while 循环实现重复请求 在运行爬虫时经常由于网络问题导致请求失败,而且逻辑没有错,此时使用此单元。

  • [iOS]循环网络请求顺序执行(信号量)

    背景 今天在开发过程中遇到需要进行循环网络请求,大体需求如下:网络请求A返回成功后,继续调用网络请求A(即:A—>...

  • ios多线程中使用信号量形成死锁,阻塞主线程

    最近在使用信号量时,遇到了一种死锁的情况。 分析:1.创建的总信号量为0,代码执行到dispatch_semaph...

  • MySQL -- 死锁

    死锁: 死锁是指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象,当多个事务...

  • 死锁与MVCC

    死锁 死锁是指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象,多个事务同时...

  • iOS 访问http网络plist设置

    现阶段iOS开发时,苹果建议使用https协议进行网络请求,当我们需要进行http协议的网络请求时需要对项目进行配...

  • 2.Mysql的死锁,及事务日志

    死锁  死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。当多个事务试...

网友评论

    本文标题:iOS for循环请求网络时,使用信号量导致死锁

    本文链接:https://www.haomeiwen.com/subject/cnlwuctx.html