How to wait for completion handler inside a @synchronized block?

1.4k Views Asked by At

I want to call a completion handler synchronously inside a critical section (using @synchronized block). I am trying to wait for completion handler using semaphore, but the semaphore signal is never called.

Here is what I am doing:

NSNumber *lock = 0;
@synchronized(lock) {
    // critical section code begins
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);
    [self someMethodWithCompletionHandler:^(BOOL result) {
        // execute completion handler
        dispatch_semaphore_signal(sema);
    }];
    // wait for completion block to finish
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    // critical section code ends
}

I believe, due to @synchronized block the completion handler is called on the same thread as the caller which results in a deadlock. Is that right? If yes, how else can this be achieved?

Thanks!

1

There are 1 best solutions below

0
On

I would avoid @synchronized and use a serial dispatch queue to serialize the work in the critical section. You can still use a semaphore to block the serial dispatch queue until the asynchronous operation is complete.

The serial dispatch queue guarantees that only one block of code can enter the critical section at a time and there is no risk of blocking the main queue.

You will need to create the serial queue during your class initialisation

@property (strong,nonatomic) dispatch_queue_t serialQueue;

- (id)init {
    if (self = [super init]) {
        self.serialQueue = dispatch_queue_create("com.example.CriticalTaskQueue", NULL);
    }
    return self;
}

- submitSomeCriticalWork() {

    dispatch_async(self.serialQueue, ^{
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);
        [self someMethodWithCompletionHandler:^(BOOL result) {
         // execute completion handler
            dispatch_semaphore_signal(sema);
        }];
    // wait for completion block to finish
     dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    // critical section code ends
   }];

}