7

Sto discutendo se passare o meno a un modello basato su GCD per accessors multi-thread. Ho utilizzato la sincronizzazione basata su lock personalizzata in accessor per anni, ma ho trovato alcune informazioni (Intro to GCD) e sembra che ci siano pro di un approccio basato su GCD. Spero di aprire qui un dialogo per aiutare me stesso e gli altri a valutare la decisione.Accessori Objective-C multi-thread: GCD vs lock

Il modello si presenta come:

- (id)something 
{ 
    __block id localSomething; 
    dispatch_sync(queue, ^{ 
     localSomething = [something retain]; 
    }); 
    return [localSomething autorelease]; 
} 

- (void)setSomething:(id)newSomething 
{ 
    dispatch_async(queue, ^{ 
     if(newSomething != something) 
     { 
      [something release]; 
      something = [newSomething retain]; 
      [self updateSomethingCaches]; 
     } 
    }); 
} 

Sul lato pro: si ottiene il beneficio di, forse, non bloccando l'accesso in scrittura; più basso overhead di serrature (forse?); sicurezza dal dimenticare di sbloccare prima di tornare da sezioni di codice critiche; altri?

Contro: La gestione delle eccezioni è inesistente, quindi è necessario codificarlo in ogni blocco in cui potrebbe essere necessario.

Questo modello è potenzialmente il metodo consigliato per la scrittura di accessori multithread?

Esistono approcci standard per la creazione di code di invio per questo scopo? In altre parole, le migliori pratiche per il trading fuori dalla granularità? Ad esempio, con i blocchi, il blocco su ciascun attributo ha una grana più fine rispetto al blocco sull'intero oggetto. Con le code di invio, potevo immaginare che la creazione di una singola coda per tutti gli oggetti creava colli di bottiglia nelle prestazioni, quindi le code per oggetto sono appropriate? Ovviamente, la risposta dipende in larga misura dall'applicazione specifica, ma ci sono noti compromessi in termini di prestazioni per valutare la fattibilità dell'approccio.

Qualsiasi informazione/intuizione sarebbe apprezzata.

+0

Proprio come un punto dati, le code e i blocchi pthread hanno un 'peso' simile (80 byte contro 64 byte, tempo di acquisizione comparabile), ma l'uso di code anziché di thread espliciti consente di risparmiare memoria cablata per i thread lato kernel (a meno che tu non gestisci con cura la tua vita thread esplicita te stesso tramite una sorta di pool) –

risposta

8

Questo schema è potenzialmente il metodo consigliato per la scrittura di accessi multithread ?

Immagino che l'abbiate scritto con una coda seriale in mente, ma non c'è motivo per questo. Considera questo:

dispatch_queue_t queue = dispatch_queue_create("com.example", DISPATCH_QUEUE_CONCURRENT); 

// same thing as your example 
- (NSString*)something { 
    __block NSString *localSomething; 
    dispatch_sync(queue, ^{ 
     localSomething = _something; 
    }); 
    return localSomething; 
} 

- (void)setSomething:(NSString*)something { 
    dispatch_barrier_async(queue, ^{ 
     _something = something; 
    }); 
} 

Legge contemporaneamente ma utilizza una barriera di invio per disabilitare la concorrenza mentre la scrittura è in corso. Un grande vantaggio di GCD è che consente letture concorrenti bloccando invece l'intero oggetto come @property (atomic).

Entrambi asyncs (dispatch_async, dispatch_barrier_async) sono più veloci dal punto di vista del client, ma più lenti da eseguire rispetto a una sincronizzazione perché devono copiare il blocco e avendo il blocco un'attività così piccola, il tempo necessario per copiare diventa significativo Preferisco che il cliente ritorni velocemente, quindi sono d'accordo.

+0

Le barriere non funzionano sulle code globali. Avresti bisogno di una coda concorrente privata. –

+0

Oh, è vero, è sui documenti, lo aggiusterò, grazie. – Jano

+0

Inoltre è possibile utilizzare dispatch_async_f per evitare Block_copy() –