信号量:没有看到我的回调方法被调用,死锁



我有两个轻量级的网络请求,我想同时执行,然后在两者都完成后,调用一个块函数。

我创建了如下方法:

- (void)loadWithCompletion:(void (^)())completion
{
    dispatch_semaphore_t customerSemaphore = dispatch_semaphore_create(0);
    dispatch_semaphore_t communitySemaphore = dispatch_semaphore_create(0);
    dispatch_async(dispatch_queue_create("mp.session.loader", DISPATCH_QUEUE_CONCURRENT), ^(void)
    {
        [_customerClient loadCustomerDetailsWithSuccess:^(MPCustomer* customer)
        {
            [self setCurrentCustomer:customer];
            dispatch_semaphore_signal(customerSemaphore);
        } error:^(NSError* error)
        {
            LogDebug(@"Got unexpected error loading customer details: %@", error);
        }];
        [_customerClient loadCommunityDetailsWithSuccess:^(MPCommunity* community)
        {
            [self setCurrentCommunity:community];
            dispatch_semaphore_signal(communitySemaphore);
        } error:^(NSError* error)
        {
            LogDebug(@"Got unexpected error loading customer details: %@", error);
        }];
    });
    dispatch_semaphore_wait(customerSemaphore, DISPATCH_TIME_FOREVER);
    dispatch_semaphore_wait(communitySemaphore, DISPATCH_TIME_FOREVER);
    if (completion)
    {
        completion();
    }
}

它最终永远等待。我看到我的两个网络请求启动,但我从未调用来自两个客户端调用的两个回调,因此两个信号量都没有信号。

为什么?

我想知道您创建的调度队列是否在运行块之前被销毁。 但是,为并发操作创建调度队列是没有意义的。 而是这样做:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void)...

更新:

另外,您是否检查过您的网络库是否未在主队列上回调?这将导致死锁。

我在这里注意到的第一件事是,如果出现错误,您将永远挂起,因为您从"成功"块而不是"失败"块发出信号量信号。 @AndyEtheridge关于从主线程调用它然后等待 NSURLConnection 回调的危险是正确的,这些回调也将在同一运行循环(您正在阻止)上传递。也就是说,这可以说是用更异步的模式更好地实现的。也许是这样的:

- (void)loadWithCompletion:(void (^)())completion
{
    dispatch_group_t group = dispatch_group_create();
    dispatch_block_t workBlock = ^(void)
    {
        [_customerClient loadCustomerDetailsWithSuccess:^(MPCustomer* customer)
         {
             [self setCurrentCustomer:customer];
             dispatch_group_leave(group);
         } error:^(NSError* error)
         {
             LogDebug(@"Got unexpected error loading customer details: %@", error);
             dispatch_group_leave(group);
         }];
        [_customerClient loadCommunityDetailsWithSuccess:^(MPCommunity* community)
         {
             [self setCurrentCommunity:community];
             dispatch_group_leave(group);
         } error:^(NSError* error)
         {
             LogDebug(@"Got unexpected error loading customer details: %@", error);
             dispatch_group_leave(group);
         }];
    });
    dispatch_queue_t bgQueue = dispatch_queue_create("mp.session.loader", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_enter(group); // for the loadCustomer call
    dispatch_group_enter(group); // for the loadCommunity call
    dispatch_async(bgQueue, workBlock);
    dispatch_group_notify(group, [NSThread isMainThread] ? dispatch_get_main_queue() : bgQueue, completion);
}

这使得调用最终完成的等待是异步的,并且如果对-loadWithCompletion:的初始调用来自主线程,则专门调用主线程上的完成。

最新更新