2016-06-23 73 views
0

这是情景:我想补充观察员监视事件&当触发事件&处理,我等待结果的回调块,如果结果是好吧,我做其他任务。如果等待超时,我只是打印错误信息。信号灯不起作用

我用信号实现与下面的简单代码上面的事情:

-(void)waitForResultThenDoOtherTask { 
    BOOL shouldPrintErr = NO; 

    // I create a semaphore 
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 

    // I have an observer with a callback, the callback is triggered when event is observed & result is passed to callback 
    [self addObserver:myObserver withCallback:callback]; 

    id callback = ^(BOOL result) { 
    // if result is YES, I signal semaphore, otherwise, set shouldPrintErr flag to YES 
    if (result) { 
     dispatch_semaphore_signal(semaphore); 
    } else { 
     shouldPrintErr = YES; 
    } 
    } 

    // wait until timeout 
    dispatch_time_t timeOut = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)); 
    dispatch_semaphore_wait(semaphore, timeOut); 

    if (shouldPrintErr) { 
    NSLog(@"TIME OUT!!!"); 
    } else { 
    // do other task 
    [self doOtherTask]; 
    } 
} 

我所说的以上功能在另一类是这样的:

// 1st call 
[object waitForEventThenDoOtherTask]; 

// this function delete local files (in another thread) 
[self deleteLocalFileInAnotherThread]; 

// 2nd call 
[object waitForEventThenDoOtherTask]; 

第一个呼叫工作正常,当事件被触发时,resultYES,信号量得到sig最后等待,doOtherTask被调用,一切都按预期工作。

第二个呼叫,当触发事件,resultYES旗语得到信号,但代码仍然在等待,直到超时,然后在打印超时错误。

为什么?即使信号量获得信号,为什么第二次调用代码仍在等待信号量?在这方面可能的原因是什么?如何让第二个电话按预期工作?

=====更新:我找到了原因,但如何解决? ====

我意识到多次调用回调,这意味着相同的信号量已被多次发信号。我认为这是我的问题的原因。但是,如何摆脱这个问题呢?那么解决方案是什么?

+0

函数是否在主线程上调用? – Code

+0

是的,它被称为主线程 –

+0

@ Leem.fin通过第二次调用你的意思是第二次调用方法waitForResultThenDoOtherTask()? – pnizzle

回答

0

我只会解释信号量的作用,我确定你已经知道了。

如果创建值为0 mySemaphore,调用wait(mySemaphore)会等待,直到另一个线程执行signal(mySemaphore),其中一个增加信号量的值,这意味着另外一个线程可以继续,如果有等待任何线程。

如果您使用值1创建它,任何调用wait(mySemaphore) 的线程都将继续运行,但等待后信号量值变为0。这意味着随后调用wait(mySemaphore)的任何线程都将等待另一个线程调用signal(mySemaphore)

如果您创建值为5的mySemaphore,则任何调用wait(mySemaphore)的线程都将继续处理并将信号量值减1(使值为4)。只要信号量不为零,wait(mySemaphore)不会使线程等待。这在很多情况下都很有用。然后当信号量变为0时调用wait(mySemaphore)的线程将等待。

话虽如此,等待的线程显然不能做任何事情,它不会超过wait(mySemaphore)点。所以,如果你想继续,另一个线程必须拨打signal(mySemaphore)。如果另一个线程在之前调用wait(mySemaphore),则等待线程可能仍然不能继续。就像在银行有一个队列,有多个服务点(信号量值)。信号量值0表示银行可用的服务点数为零。值3表示三个服务点。如果有5个人在等待,并且一个展位变得可用,那么首先等待的人(位于队列前面的人)将被送达。

我们解决你的情况(一开始),确保else(result==NO)也有信号旗语...

if (result) 
{ 
    dispatch_semaphore_signal(semaphore); 
} 
else 
{ 
    shouldPrintErr = YES; 
    dispatch_semaphore_signal(semaphore); 
} 

不要让主线程等待,任何可能会很长而不是UI相关应该在后台线程。因此,将等待部分的代码更改为:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{ 

    dispatch_time_t timeOut = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)); 
    dispatch_semaphore_wait(semaphore, timeOut); 

    if (shouldPrintErr) 
    { 
     NSLog(@"TIME OUT!!!"); 
    } 
    else 
    { 
     // do other task, dispatch back onto main thread if required. 
     [self doOtherTask]; 
    } 
});