9

ho una coda di invio di serie creata con:dispatch_async vs ordine di esecuzione dispatch_sync

dispatch_queue_t serialQueue = dispatch_queue_create("com.unique.name.queue", DISPATCH_QUEUE_SERIAL); 

voglio usare questa coda di serie per garantire la sicurezza dei thread per l'accesso di classe, mentre si fa automaticamente il lavoro in modo asincrono che non ha bisogno di ritorna al thread chiamante.

- (void)addObjectToQueue:(id)object 
{ 
    dispatch_async(serialQueue, ^{ 
     // process object and add to queue 
    }); 
} 

- (BOOL)isObjectInQueue:(id)object 
{ 
    __block BOOL returnValue = NO; 
    dispatch_sync(serialQueue, ^{ 
     // work out return value 
    }); 
    return returnValue; 
} 

Se chiamo l'addObjectToQueue: metodo, poi subito chiamare l'isObjectInQueue: metodo, essi sono garantiti per essere eseguito nello stesso ordine, o lo/la potevano isObjectInQueue eseguire per primo?

In altre parole, dispatch_async esegue esattamente lo stesso di dispatch_sync (pianificando immediatamente il blocco) eccetto che non blocca il thread chiamante?

Ho visto domande simili con risposte andando in entrambe le direzioni, quindi sto cercando una risposta definitiva, preferibilmente supportata dalla documentazione Apple.

+2

"Se chiamo il metodo addObjectToQueue :, quindi, richiamo immediatamente il metodo isObjectInQueue:, sono garantiti per l'esecuzione nello stesso ordine o will/potrebbe eseguire isObjectInQueue per primo?" chiedendo questo probabilmente vuoi dire "Potremmo chiedere l'oggetto prima che fosse aggiunto alla coda?". Perché, ovviamente, 2 metodi vengono eseguiti in modo che vengano chiamati se chiamati sullo stesso thread. – krafter

risposta

13

Sono garantiti per essere eseguiti nello stesso ordine?

Sì.

Will/could isObjectInQueue esegue prima?

Sì.

Il motivo del sì per entrambe le risposte è che è necessario considerare il threading. Il che è presumibilmente il motivo per cui stai usando la coda seriale in primo luogo. Stai rendendo sicuro l'accesso a quel thread delle code.

Fondamentalmente, i blocchi verranno eseguiti nell'ordine in cui vengono inseriti nella coda seriale. Questo è garantito al 100%. Tuttavia, se più thread vengono eliminati, allora un thread potrebbe entrare per primo a leggere qualcosa dalla coda prima che un altro abbia avuto la possibilità di aggiungerlo.

In altre parole, fa dispatch_async eseguire esattamente lo stesso come dispatch_sync (programmando il blocco immediatamente) tranne che non blocca il thread chiamante?

Proprio così. In entrambi i casi il blocco viene aggiunto alla coda. Viene aggiunto immediatamente. dispatch_sync aspetta che il blocco termini prima di tornare, mentre dispatch_async restituisce immediatamente.

+2

Diritto; oppure, per sommare, i blocchi su una coda seriale verranno eseguiti nell'ordine aggiunto e quell'ordine sarà deterministico solo quando si 'dispatch_async()/dispatch_sync()' da un singolo thread. Se multi-thread e hai bisogno di ordine, dovrai fornire un meccanismo di sincronizzazione. Probabilmente avrai bisogno di un indicatore di "freschezza" per il valore di ritorno di "isObjectInQueue:" in quanto ciò potrebbe probabilmente perdere rapidamente validità in un ambiente concorrente. Cioè la concorrenza è difficile. – bbum

+0

Anche se questa discussione è vecchia mi piacerebbe farla rivivere per chiarire alcuni momenti. 1. "Will/potrebbe eseguire isObjectInQueue per primo? Sì." Andrew chiede se ** METHODS ** potrebbe essere eseguito in ordine casuale in modo che vengano chiamati uno dopo l'altro, non blocchi all'interno di dispatch_async. ma: 2. Probabilmente intende bloccare se stesso. :). Ma ancora, un blocco può essere eseguito prima dell'altro se aggiunto per ultimo sulla coda seriale? ** "dispathc_async - Invia un blocco per l'esecuzione asincrona su una coda di invio e restituisce immediatamente. Le chiamate a questa funzione restituiscono sempre immediatamente _after_ il blocco è stato inviato." ** – krafter

2

Immagino che la tua domanda sia, il thread principale continuerà a funzionare mentre dispatch_async sta ancora eseguendo l'operazione di coda? Presumo che non lo farà, perché meriterebbe una menzione esplicita. Se non altro, ho trovato questo in dispatch_async.3 che suggerisce questo è il caso:

Concettualmente, dispatch_sync() è un wrapper conveniente intorno dispatch_async() con l'aggiunta di un semaforo di attesa per il completamento del blocco, e un wrapper attorno al blocco per segnalare il completamento di .

E in effetti, se si segue il codice sorgente per dispatch_async in queue.c vedrete che il blocco è in coda in primo piano, e solo dopo che, l'esecuzione ritorna al codice che chiama dispatch_async. Pertanto se la coda è seriale, dispatch_async seguita da dispatch_syncdallo stesso thread verranno messi in coda i blocchi in ordine.

Perché dispatch_sync bloccherà fino a quando il blocco (e tutti i blocchi precedenti in una coda seriale) saranno eseguiti, quindi il codice sarebbe corretto. isObjectInQueue: segnalerà correttamente se l'oggetto aggiunto prima è in coda.

modifica: in un ambiente con multithreading avrei scritto il codice precedente come:

- (void)addObjectToQueue:(id)object 
{ 
    dispatch_barrier_async(_queue, ^{ 
     // process object and add to queue 
    }); 
} 

- (BOOL)isObjectInQueue:(id)object 
{ 
    __block BOOL returnValue = NO; 
    dispatch_sync(_queue, ^{ 
     // work out return value 
    }); 
    return returnValue; 
} 

perché l'esecuzione di ogni metodo può essere differito in qualsiasi punto a favore di un altro filo.

+0

Dalla lettura della documentazione di dispatch_barrier_async, se si sta utilizzando una coda seriale creata da soli, il comportamento sarà identico a dispatch_async. È corretto? – Andrew

+0

Sì. Il codice sopra presuppone l'uso di una coda concorrente per un ambiente con multithreading perché la serializzazione delle letture sarebbe un blocco stradale inutile. Con una coda seriale, tuttavia, non vi sono blocchi in esecuzione simultaneamente per applicare la barriera, quindi un dispatch_barrier_async è equivalente a un dispatch_async. – Jano

+1

'dispatch_barrier_async()' non fa nulla su una coda seriale perché, per definizione, tutti i blocchi in fila prima saranno eseguiti dal momento in cui viene eseguito il blocco della barriera. Incide solo sulle code concorrenti. – bbum