【问题标题】:Wait for asynchronous block to finish - signal (seems) do not work等待异步块完成 - 信号(似乎)不起作用
【发布时间】:2015-10-30 13:51:40
【问题描述】:

我正在使用 cryptotokenkit 从智能卡发送/接收数据。用例是,在我做其他事情之前,我必须得到卡片 API 的响应。

在我的例子中,我发现这条线总是在 kMaxBlockingTimeSmartCardResponse (= 10) 秒后被调用。 来自

dispatch_semaphore_t sema = dispatch_semaphore_create(0);

直接去

dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kMaxBlockingTimeSmartCardResponse * NSEC_PER_SEC));
        dispatch_semaphore_wait(sema, timeout);

然后等待 10 秒来进行块调用。它不是块回调延迟。如果我将调度时间设置为 20 或 30 秒,它会等待 20 或 30 秒执行。等待调用真正等待指定的时间然后执行回调块。

我做错了什么?我想知道这是否与 adObserver 有关。

- (void) updateSlots {
    self.slotNames = [self.manager slotNames];
    self.slotModels = [NSMutableArray new];
    self.slots = [NSMutableArray new];

    if([self.slotNames count] > 0)
    {
        for (NSString *slotName in self.slotNames)
        {
            NSLog(@"SmartCard reader found: %@", slotName);
            // semaphore BLOCK starts
            dispatch_semaphore_t sema = dispatch_semaphore_create(0);
            [self.manager getSlotWithName:slotName reply:^(TKSmartCardSlot *slot)
             {
                 if (slot) {
                     SCSlotModel *slotModel = [SCSlotModel new];
                     [self.slotModels addObject:slotModel];

                     [self.slots addObject:slot];
                     [slot addObserver:self forKeyPath:@"state"
                               options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld | NSKeyValueObservingOptionInitial
                               context:nil];

                     slotModel.suffixedName = slotName; // NOT slot.name; original name is suffixed with 01, 02 etc.
                     slotModel.slot = slot;
                     slotModel.cardStatus = [CardUtil mapCardStatus:slot.state];
                     DLog(@"slot: %@, slotmodel: %@",slot.name, slotModel);
                 } else {
                     NSLog(@"Did not find slot with name: %@", slotName);
                 }
                 dispatch_semaphore_signal(sema);
             }];
            dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kMaxBlockingTimeSmartCardResponse * NSEC_PER_SEC));
            dispatch_semaphore_wait(sema, timeout);
            // semaphore BLOCK ends
            self.errorCode = SCPNoError;
        }

    } else {
        NSLog(@"No slot available.");
        self.errorCode = SCPErrorReaderNotFound;
    }
}

getSlotWithName 是来自TKSmartCardSlotManager 的方法

/// Instantiates smartcard reader slot of specified name.  If specified name is not registered, returns nil.
- (void)getSlotWithName:(NSString *)name reply:(void(^)(TKSmartCardSlot *__nullable slot))reply;

但在其他地方,对于相同类型的异步调用,它按预期工作。

- (BOOL) beginSession:(TKSmartCard *)card
{
    __block BOOL response = NO;
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);
    [card beginSessionWithReply:^(BOOL success, NSError *error) {
        response = success;
        if (!success) {
            NSLog(@"Could not begin session.");
        }
        if (error) {
            NSLog(@"Could not begin session with error %@", error);
        }
        dispatch_semaphore_signal(sema);
    }];

    dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kMaxBlockingTimeSmartCardResponse * NSEC_PER_SEC));
    dispatch_semaphore_wait(sema, timeout);
    return response;
}

【问题讨论】:

  • 您将从应用异步编程风格中受益。由于您的updateSlots 方法使用异步方法,因此该方法也变为异步:将完成块的参数添加到updateSlots 并在getSlotWithName 的完成处理程序reply 中调用此块。然后使用延续调用updateSlots,即完成块-并执行您想做的任何事情以继续。
  • 谢谢。我会试试的。但在其他地方它按预期工作。用那部分更新了我的代码。

标签: xcode macos callback objective-c-blocks semaphore


【解决方案1】:

getSlotWithName:reply: 在哪个线程上调用它的回复处理程序? 例如,如果在主线程上执行 updateSlots 并且您正在执行以下操作:

... // some async operation in `getSlotWithName:reply:` has completed
dispatch_async(dispatch_get_main_queue(), ^{
    reply(slot)
});

那么你最终会在主线程上排队你的回复,但是主线程当前被你的信号量锁定。

确保您从已锁定线程以外的线程调用 dispatch_semaphore_signal() 应该可以解决您的问题。


旁注: GCD 和信号量在这里可以解决问题,但有更好的方法可以在异步操作完成后执行操作,而不是让线程被锁定。例如,委托回调。
这里没有足够的信息来提出任何确切的建议,但还有其他选择:)

【讨论】:

    猜你喜欢
    • 2019-01-03
    • 2020-10-04
    • 1970-01-01
    • 2017-02-15
    • 2019-06-16
    • 2018-03-05
    • 2016-01-31
    • 1970-01-01
    • 2019-05-31
    相关资源
    最近更新 更多