在我的情况下,信号量没有按预期工作 [英] semaphore doesn't work as expected in my case

查看:44
本文介绍了在我的情况下,信号量没有按预期工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是场景:我想添加一个观察者来监控事件&当事件被触发时处理后,我在回调块中等待结果,如果结果很好,我会做其他任务.如果等待超时,我只打印错误信息.

This is the scenario: I want to add an observer to monitor events & when an event is triggered & processed, I wait for the result in callback block, if result is fine, I do other task. If wait timeout, I just print error message.

我使用信号量通过以下简单代码来实现上述功能:

I use semaphore to achieve the above thing with the following simple code:

-(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];
  }
}

我在另一个类中调用上述函数,如下所示:

I call the above function in another class like this:

// 1st call
[object waitForEventThenDoOtherTask];

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

// 2nd call
[object waitForEventThenDoOtherTask];

第一次调用工作正常,当事件被触发且resultYES时,semaphore得到信号等待停止,doOtherTask 被调用,一切都按预期进行.

The 1st call works fine, when event is triggered and result is YES, semaphore gets the signal and waiting stops, doOtherTask is called, everything works as expected.

但是对于第二次调用,当事件被触发时,resultYESsemaphore得到信号,但代码仍在等待超时,然后打印超时错误.

But for the 2nd call, when event is triggered, result is YES, semaphore gets signal, but the code is still waiting until timeout, then timeout error is printed.

为什么?为什么即使信号量获得信号,第二次调用代码仍然在等待信号量?在这种情况下可能的原因是什么?以及如何使第二次通话也按预期工作?

Why? Why the 2nd time call code still waiting for semaphore even though semaphore gets the signal? What could be the possible reason in this context? And how to make the 2nd call work as expected as well?

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

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

I realize that the callback get called multiple times, which means the same semaphore has been signaled multiple times. I think that is the reason for my problem. But, how to get rid of this problem? What is the solution then?

推荐答案

我只会解释信号量的作用,我相信你已经知道了.

I'll just explain what the semaphore does, Im sure you already know.

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

If you create mySemaphore with value 0, any thread that calls wait(mySemaphore) will wait until another thread does signal(mySemaphore), which increases the semaphore value by one, meaning one other thread can continue, if any was waiting.

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

If However you create it with value 1, any thread that calls wait(mySemaphore) will continue to run, BUT the semaphore value becomes 0 after the wait. Which means any thread that subsequently calls wait(mySemaphore) will wait until another thread calls signal(mySemaphore).

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

If you create mySemaphore with a value of 5, any thread that calls wait(mySemaphore) will continue to process and also reduce the semaphore value by one (making the value 4). For as long as the semaphore is not zero wait(mySemaphore) will not make the thread wait. This is useful in a number of scenarios. A thread that then calls wait(mySemaphore) when the semaphore has become 0 will then wait.

话虽如此,一个正在等待的线程显然不能做任何事情,它不会比wait(mySemaphore)点更进一步.所以,如果你想让它继续,另一个线程必须调用 signal(mySemaphore).如果另一个线程在它之前调用了 wait(mySemaphore),等待的线程可能仍然不会继续.这就像在银行有一个队列,有多个服务点(信号量值).信号量值为 0 表示银行的可用服务点为零.值为 3 表示三个发球点.如果有 5 个人在等待并且有一个摊位可用,那么先等待的人(排在队列前面的那个人)就会得到服务.

Having said this, a thread that is waiting obviously cant do anything, it will not go further than the wait(mySemaphore) point. So, if you want it to continue, another thread has to call signal(mySemaphore). The waiting thread may still not continue if another thread had called wait(mySemaphore) before it. Its like having one queue at the bank, with multiple serving point (semaphore value). A semaphore value of 0 means zero available serving points at the bank. A value of 3 means three serving points. If 5 people are waiting and one booth becomes available then the person that waited first (the one at the front of the queue) then gets served.

现在要解决您的情况(作为开始),请确保 else(result==NO) 也向信号量发出信号...

Now to address your case (for a start), make sure else(result==NO) also signals the semaphore...

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

另外 不要让主线程等待,任何可能很长但与 UI 无关的东西都应该在后台线程中.所以把wait部分的代码改成这样:

Also Do not make the main thread wait, anything that can be lengthy and yet not UI related should be in a background thread. So change the code at the wait section to this:

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];
    }
});

更新:

看到你解决了你最初的问题,剩下的问题是信号量的过度信号,你可以做的(我以前做过)是为 dispatch_semaphore_t 创建一个包装类.我已经这样做了,但不能共享代码,因为它在法律上不属于我.您将在该类上拥有一个名为 maximumValue 的整数属性.该类将有一个信号和等待方法,该方法递增或递​​减一个内部整数,用于跟踪信号量的值.信号将根据最大值决定是否发出信号.我相信你应该能够从 semaphore._value 做到这一点.我希望这对某人有所帮助.

Seeing that you fixed your initial issue, and that the remaining issue is the over-signaling of the semaphore, what you can do (I have done this before) is to create a wrapper class for dispatch_semaphore_t. I have done this but can not share the code as it legally does not belong to me. You will have an integer property on that class called maximumValue. The class will have a signal and wait method which increment or decrement an internal integer that it uses to track the value of the semaphore. The signal will determine whether to signal or not depending on the maximum value. I believe you should be able to do that anyway from semaphore._value. I hope this helps someone.

这篇关于在我的情况下,信号量没有按预期工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆