美文网首页
dispatch_semaphore使用崩溃问题

dispatch_semaphore使用崩溃问题

作者: 水水兔 | 来源:发表于2019-07-29 11:20 被阅读0次

崩溃问题不是作者本人遇到的哈,虽然现在没遇到,不代表以后不会遇到,而且如果真遇到这种崩溃,很难查出原因,因为根本不会想到是信息量释放引起的,所以排查此崩溃很容易走弯路,在此做下总结,以此共勉。
我们看个能复现此崩溃的demo

  dispatch_semaphore_t semp = dispatch_semaphore_create(1);
    dispatch_block_t block = ^{
        dispatch_semaphore_signal(semp);
        NSLog(@"signal");
    };

    NSMutableArray *array = [NSMutableArray array];
    for (NSInteger i = 0; i < 4; i++) {
        NSLog(@"wait");
        dispatch_semaphore_wait(semp, DISPATCH_TIME_FOREVER);
        if (i > 2) {//当I大于2时,只执行 wait ,没执行signal
            break;
        }else{ //当I小于等于2时,signal与wait是配对的
            block();
        }
    }

控制台输出如下:

019-07-29 11:12:02.300190+0800 TEST[10987:950615] +[CATransaction synchronize] called within transaction
2019-07-29 11:12:02.439848+0800 TEST[10987:950615] wait
2019-07-29 11:12:02.439934+0800 TEST[10987:950615] signal
2019-07-29 11:12:02.439962+0800 TEST[10987:950615] wait
2019-07-29 11:12:02.439986+0800 TEST[10987:950615] signal
2019-07-29 11:12:02.440009+0800 TEST[10987:950615] wait
2019-07-29 11:12:02.440032+0800 TEST[10987:950615] signal
2019-07-29 11:12:02.440054+0800 TEST[10987:950615] wait

上面代码执行后,wait数大于signal次数,即信号量的当前值小于初始化,超过函数作用域后,会释放信号量,此时会崩溃产生

原因是信号量的销毁会调用_dispatch_semaphore_dispose函数,而此函数会执行信号当前值与初始化值的比较,如果小于初始化值,则直接抛出崩溃。
我们看下此函数的原码:

static void
_dispatch_semaphore_dispose(dispatch_semaphore_t dsema)
{
    //信号量的当前值小于初始化,会发生闪退。因为信号量已经被释放了
    if (dsema->dsema_value < dsema->dsema_orig) {
        DISPATCH_CLIENT_CRASH(
                "Semaphore/group object deallocated while in use");
    }

#if USE_MACH_SEM
    kern_return_t kr;
    //释放信号,这个信号是dispatch_semaphore使用的信号
    if (dsema->dsema_port) {
        kr = semaphore_destroy(mach_task_self(), dsema->dsema_port);
        DISPATCH_SEMAPHORE_VERIFY_KR(kr);
    }
    //释放信号,这个信号是dispatch_group使用的信号
    if (dsema->dsema_waiter_port) {
        kr = semaphore_destroy(mach_task_self(), dsema->dsema_waiter_port);
        DISPATCH_SEMAPHORE_VERIFY_KR(kr);
    }
#elif USE_POSIX_SEM
    int ret = sem_destroy(&dsema->dsema_sem);
    DISPATCH_SEMAPHORE_VERIFY_RET(ret);
#endif

    _dispatch_dispose(dsema);
}

总结:

当信号量的当前值小于初始化,释放信号量时,会导致崩溃,简而言之就是,signal的调用次数一定要大于等于wait的调用次数,否则导致崩溃。

参考:

相关文章

网友评论

      本文标题:dispatch_semaphore使用崩溃问题

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