2017-09-26 149 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 
    }]; 

}