超时后不会触发dispatch_semaphore_wait

时间:2015-07-30 15:30:23

标签: objective-c grand-central-dispatch

我想构建一个NSOperation,它在开始后超时为10秒,并且可以在任何时候通过事件由另一个线程结束。我还使用NSOperationQueue来管理这样的更多操作,它一次只能计算一个(maxConcurrentOperationCount = 1)。为此,我考虑了使用dispatch_semaphore的实现,如下所示:

@implementation CustomOperation

dispatch_semaphore_t semaphore;
-(void) main {
    @autoreleasepool {

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(shouldFinishWaiting:) name:@"myCustomEvent" object:nil];

        semaphore = dispatch_semaphore_create(0);

        [self doStuff];

        dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)));
        [[NSNotificationCenter defaultCenter] removeObserver:self name:@"myCustomEvent" object:nil];
    }
}


-(void) shouldFinishWaiting {
    NSLog(@"[WatchOperation]: Should finish waiting! %@", self);
    dispatch_semaphore_signal(semaphore);
}

@end

我遇到的问题是,在用户启动应用程序的许多次中,第一次操作将无法完成,直到事件被触发(这可能在30分钟后发生)。超时不会被考虑在内。我在一些用户的日志中注意到这一点,所以我无法重现它。可能出现什么问题导致dispatch_semaphore_wait无法执行?

稍后编辑:我错误地认为-doStuff是异步的。它似乎不是。我用以下代替:

dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{ 
    [self doStuff]; 
});

,但操作已经在串行队列'用户启动'上。正如我所看到的那样,它会创建另一个精确的线程,每次都会发生这种情况吗?这样安全吗?

3 个答案:

答案 0 :(得分:1)

我认为调度信号量不会出错。也许你的-doStuff花了太多时间。确保您正在执行以下操作:
1.方法[self doStuff];是异步的,它调度到一个不同于当前线程的线程(如果你想使用信号量进行10秒超时,则调度到当前线程没有意义)。
2.确保在-doStuff中检查self.isCancelled。

另外,我建议您根据自己的要求采用略有不同的设计方法(如果我理解正确的话) -
1.您的NSOperation总是可以从我的调用取消对象的任何外部线程中取消,因此不需要复杂的基于NSNotification的方法,只需检查isCancelled并覆盖-cancel方法。
2.对于10秒超时,您可以使用信号量方法,但只需要一个执行信号量等待的DIFFERENT线程。然后,该线程可以在10秒后从内部取消您的任务。

答案 1 :(得分:0)

我认为你的信号量不会成为全局变量......

根据您使用的是32位还是64位,NSEC_PER_SEC可能是32位值,它会溢出并在乘以10时变为负值。将10替换为10.0。可以解决问题,可能根本不做任何事情。

答案 2 :(得分:0)

@selector(shouldFinishWaiting :)应该是@selector(shouldFinishWaiting)。没有冒号,因为该方法没有参数。