2013-03-13 16 views
13

in Documenti di Apple, si dice:Come si crea un deadlock in Grand Central Dispatch?

Importante: Non si dovrebbe mai chiamare il dispatch_sync o dispatch_sync_f funzione da un compito che sta eseguendo nella stessa coda che si è pianificazione per passare alla funzione. Ciò è particolarmente importante per le code seriali , che sono garantite come deadlock, ma dovrebbero anche essere evitate per le code simultanee.

Come si scrive il codice per fare esattamente questo?

+0

Volete esempio di codice che crea un punto morto? – Vladimir

+0

Sì, per l'apprendimento – BlackMouse

+1

Vedere anche [questa domanda] (http://stackoverflow.com/questions/10330679/how-to-dispatch-on-main-queue-synchronously-without-a-deadlock) per un esempio realistico che può facilmente deadlock. – zoul

risposta

20

Una situazione di stallo intenzionale su una certa coda:

dispatch_queue_t queue = dispatch_queue_create("my.label", DISPATCH_QUEUE_SERIAL); 
dispatch_async(queue, ^{ 
    dispatch_sync(queue, ^{ 
     // outer block is waiting for this inner block to complete, 
     // inner block won't start before outer block finishes 
     // => deadlock 
    }); 

    // this will never be reached 
}); 

E 'chiaro qui che i blocchi esterne ed interne sono in funzione sulla stessa coda. La maggior parte dei casi in cui ciò si verificherà si trova in luoghi in cui è meno ovvio su che coda è attivo il chiamante di dispatch_sync. Ciò si verifica in genere in uno stack (profondamente) nidificato in cui si sta eseguendo codice in una classe originariamente avviata su una determinata coda e per errore si chiama uno dispatch_sync nella stessa coda.

+0

In caso di stallo ... l'interfaccia utente non dovrebbe essere bloccata? – BlackMouse

+2

@ user1251004 Solo se la coda principale è bloccata. –

+2

In questo esempio solo la 'coda' creata è bloccata. La coda principale continua felicemente a funzionare. –

7

semplice codice che crea situazione di stallo:

dispatch_queue_t q = dispatch_queue_create("deadlock queue", DISPATCH_QUEUE_SERIAL); 

NSLog(@"1"); 
dispatch_async(q, ^{ 
    NSLog(@"2"); 
    dispatch_sync(q, ^{ 
     NSLog(@"3"); 
    }); 
    NSLog(@"4"); 
}); 
NSLog(@"5"); 

uscita Log:

1 
5 
2 

blocco Qui interno è programmato per essere eseguito su coda di serie q ma non può funzionare fino a quando blocco corrente è finito, mentre il blocco corrente, a sua volta, attende interno per finire come lo chiamavamo in modo sincrono.

4

Il modo più semplice per bloccare è quello dispatch_sync sulla coda corrente:

dispatch_sync(dispatch_get_current_queue(), ^{}); 

Questo blocca quando la coda corrente è una coda seriale, ad esempio la coda principale.

0

In ultima sintassi Swift:

let queue = DispatchQueue(label: "label") 
queue.async { 
    queue.sync { 
     // outer block is waiting for this inner block to complete, 
     // inner block won't start before outer block finishes 
     // => deadlock 
    } 
    // this will never be reached 
}