2017-09-26 127 views
0

我想在临界区内同步调用一个完成处理程序(使用@synchronized block)。我试图等待使用信号量的完成处理程序,但信号量信号永远不会被调用。如何等待@synchronized块内的完成处理程序?

下面是我在做什么:

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 
} 

我相信,由于@synchronized块完成处理程序被调用同一个线程,导致死锁的呼叫者。是对的吗?如果是的话,还能如何实现?

谢谢!

+0

它通常是一个坏主意,试图使异步事情同步过程中创建的串行队列。你需要确保'someMethodWithCompletionHandler'既能完成它的工作,又能将不同的队列上的完成处理程序分派给你用'等待'来阻塞的那个队列。如果你在主队列中等待,那很糟糕。添加一个同步块使其更加复杂,因为您现在有第二个潜在的等待和死锁触发器。 – Paulw11

+0

与其使用@syncrhonized块,我会在专用串行调度队列上异步调度整个关键段,并在另一个实用程序队列或主队列上异步调度'someMethodWithCompletionHandler'。然后你的信号量可以安全地阻止你的私人队列。 – Paulw11

+0

但我希望临界区代码是同步的。不要将整个临界区异步调度到另一个串行线程使其异步?在临界区完成后应执行的临界区之后,我有代码。 –

回答

0

我会避免@synchronized并使用串行调度队列来序列化关键部分中的工作。您仍然可以使用信号量来阻塞串行调度队列,直到异步操作完成。

串行调度队列保证一次只有一个代码块可以进入临界区,并且不存在阻塞主队列的风险。

你需要你的类初始化

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

}