0

Ich möchte eine Completion-Handler in einem kritischen Abschnitt (@synchronized Block) synchron aufrufen. Ich versuche, mit Semaphor auf den Beendigungshandler zu warten, aber das Semaphorsignal wird nie aufgerufen. HierWie man auf den Vervollständigungshandler in einem @ synchronisierten Block wartet?

ist, was ich tue:

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 
} 

Ich glaube, aufgrund @synchronized Block der Abschluss-Handler auf dem gleichen Thread wie der Aufrufer aufgerufen wird, die in eine Sackgasse führt. Ist das richtig? Wenn ja, wie kann dies sonst erreicht werden?

Danke!

+0

es ist generell eine schlechte Idee schaffen, um zu versuchen und asynchrone Dinge synchron zu machen. Sie müssen sicherstellen, dass 'someMethodWithCompletionHandler' beide seine Arbeit verrichtet und den Completion-Handler in einer anderen Warteschlange an den Block sendet, den Sie mit Ihrer 'wait' blockiert haben. Wenn Sie auf die Hauptwarteschlange warten, ist das sehr schlecht. Das Hinzufügen eines synchronisierten Blocks macht es nur noch komplizierter, da Sie jetzt einen zweiten potenziellen Deadlock-Hold-and-Wait-Trigger haben. – Paulw11

+0

Anstatt einen @ syncronisierten Block zu verwenden, würde ich den gesamten kritischen Abschnitt asynchron in einer privaten seriellen Dispatch-Warteschlange absetzen und 'someMethodWithCompletionHandler' asynchron an eine andere Dienstwarteschlange oder die Hauptwarteschlange senden. Dann kann Ihr Semaphor Ihre private Warteschlange sicher blockieren. – Paulw11

+0

Aber ich möchte kritischen Abschnitt Code synchron sein. Versenden Sie nicht ganze kritische Abschnitt asynchron zu einem anderen seriellen Thread asynchron machen? Ich habe Code nach dem kritischen Abschnitt, der nach dem kritischen Abschnitt ausgeführt werden soll. –

Antwort

0

Ich würde @synchronized vermeiden und eine serielle Dispatch-Warteschlange verwenden, um die Arbeit im kritischen Abschnitt zu serialisieren. Sie können weiterhin einen Semaphor verwenden, um die serielle Dispatch-Warteschlange zu blockieren, bis der asynchrone Vorgang abgeschlossen ist.

Die serielle Dispatch-Warteschlange garantiert, dass immer nur ein Codeblock in den kritischen Abschnitt eindringen kann und es kein Risiko gibt, die Hauptwarteschlange zu blockieren.

Sie müssen die serielle Warteschlange während Ihrer Klasse Initialisierung

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

} 
Verwandte Themen