samedi 25 juin 2016

wait for callback result then continue on main thread (with semaphore)


I have a function which adds an observer on main thread, the callback of the observer is running in another thread, if the callback result is YES, I continue do another task on main thread, otherwise I print error.

Here is the code, I use semaphore to achieve it:

dispatch_queue_t semQueue;

-(void) myFunc {
  /*MAIN THREAD*/
  // I use GCD serial queue to signal semaphore, so that it can be thread safe
  semQueue = dispatch_queue_create( "my.sem.queue", DISPATCH_QUEUE_SERIAL);

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

  // add observer with callback
  [self addObserver:myObserver withCallback:^(BOOL result){
     /* CODE HERE IS RUNNING IN ANOTHER THREAD*/
     // if result is YES, I signal the semaphore to continue doing another task
     if (result){
        dispatch_sync(resultQueue,^{
                // signal semaphore
                dispatch_semaphore_signal(semaphore);
                // log
                NSLog("semaphore signaled");
            });
       }
  }];

  /*MAIN THREAD*/
  // semaphore waits for the signal, timeout is 20seconds
  dispatch_time_t timeOut = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(20 * NSEC_PER_SEC));
  long waitResult = dispatch_semaphore_wait(semaphore, timeOut);

  // if successful do other task, otherwise, print error
  if (waitResult == 0) {
     [self doAnotherTask];
  } else {
     print("Failed");
  }
}

So, to recap, what I want to achieve with this function is to wait for the result from a callback of my observer, if it is successful, I continue do another task, otherwise print error. (callback is running in another thread.)

As you see in code, I use GCD to signal semaphore to make it thread safe.

When I run my function multiple times consecutively like this:

// run myFunc
[service myFunc];
[self doSimpleTaskInMainThread];
// run myFunc
[service myFunc];
[self doSimpleTaskInMainThread];
// run myFunc
[service myFunc];
...

When calling myFunc for the 1st & 2nd time are working fine, after that the other calls sometimes hanging in the place after semaphore is signaled. I see the log "semaphore signaled", then code is hanging for 20 seconds timeout, and then, it goes to main thread checks the result is YES, and it starts to do another task.

My Questions:

  1. Why it is hanging even though semaphore is signaled ?
  2. Is there another way other than using semaphore to achieve this?
  3. Is it fine to use GCD to update that boolean flag resultSucceed ? Other better options?

Aucun commentaire:

Enregistrer un commentaire