2014-09-11 10 views
6

std::shared_ptr è sicuro per essere thread-safe. Non so quale meccanismo utilizzi le tipiche implementazioni per garantire questo, ma sicuramente deve avere un sovraccarico. E quell'overhead sarebbe presente anche nel caso in cui la tua applicazione fosse a thread singolo.Qual è l'overhead di shared_ptr che è thread-safe?

È il caso precedente? E se è così, vuol dire che viola il principio di "non paghi per ciò che non usi", se non stai utilizzando le garanzie di sicurezza del thread?

+0

Dalla memoria, la libreria Loki dispone di puntatori intelligenti con una politica di sicurezza del thread che risolve questo problema. –

+0

FYI, http://stackoverflow.com/questions/15129263/is-there-a-non-atomic-equivalent-of-stdshared-ptr-and-why-isnt-there-one-in –

risposta

4

Almeno nel codice boost su i386, boost::shared_ptr è stato implementato utilizzando un'operazione CAS atomica. Ciò significa che mentre ha un sovraccarico, è piuttosto basso. Mi aspetto che qualsiasi implementazione di std::shared_ptr sia simile.

In loop stretti nel codice numerico ad alte prestazioni ho trovato alcuni accelerazioni passando a puntatori grezzi e facendo molta attenzione. Ma per codice normale - non me ne preoccuperei.

+1

Sono abbastanza sicuro tutte le principali implementazioni utilizzano l'atomica. So che Microsoft lo fa, per esempio. –

+0

@VioletGiraffe: non tutte le piattaforme hardware supportano i contatori atomici senza blocco. I vecchi ARM non lo fanno, per esempio. –

+2

Le operazioni atomiche sono piuttosto costose. L'ultima volta che ho misurato, credo fosse tipicamente di circa 20 ns per operazione atomica su una tipica CPU Intel. Nell'ordine di 100 volte più lento di una normale operazione. –

8

Se controlliamo fuori cppreference pagina dedicata std::shared_ptr affermano quanto segue nella Note di attuazione sezione:

per soddisfare i requisiti di sicurezza filo, i contatori di riferimento sono tipicamente incrementato e decrementato usando std::atomic::fetch_add con std::memory_order_relaxed.

E 'interessante notare un'implementazione reale, ad esempio il documento libstdc++ implementazione here dice:

Per la versione di shared_ptr nel libstdC++ il compilatore e la biblioteca sono fissi, il che rende le cose molto più semplici : non abbiamo un CAS atomico o , per i dettagli vedere Lock Policy qui sotto.

Il Selezionando la politica di blocco sezione dice (sottolineatura mia):

V'è una sola classe _Sp_counted_base, che è un modello con parametri sul enum __gnu_cxx :: _ Lock_policy. L'intera famiglia di classi è parametrizzata sulla politica di blocco, fino a __shared_ptr, __weak_ptr e __enable_shared_from_this. L'attuale classe std :: shared_ptr eredita dalla __shared_ptr con la politica di blocco parametro selezionata automaticamente in base al modello di thread e piattaforma che libstdC++ configurato per, in modo che i migliori disponibili modello di specializzazione sarà utilizzato. Questo design è necessario perché non sarebbe conforme per shared_ptr per avere un parametro aggiuntivo modello , anche se aveva un valore predefinito. Le politiche disponibili sono:

[...]

3._S_Single

Questa politica utilizza un add_ref_lock non rientrante() senza bloccaggio. Viene utilizzato quando libstdC++ viene creato senza --enable-threads.

e ulteriormente dice (sottolineatura mia):

Per tutte e tre le politiche, con incrementi di conteggio di riferimento e decrementi sono fatto tramite le funzioni in ext/atomicity.h, che rilevano se il programma è multi-threaded. Se nel programma esiste un solo thread di esecuzione, vengono utilizzate operazioni non atomiche meno costose.

Quindi almeno in questa implementazione non si paga per quello che non si usa.

+1

"memory_order_relaxed \t Operazione rilassata: non ci sono vincoli di sincronizzazione o di ordinamento, solo l'atomicità è richiesta per questa operazione." Questo * non * sembra giusto! – curiousguy

Problemi correlati