2011-12-13 10 views
14

Ora che C++ è l'aggiunta di thread_local storage come caratteristica del linguaggio, mi chiedo alcune cose:Il costo di thread_local

  1. Qual è il costo di thead_local probabile che sia?
    • In memoria?
    • Per operazioni di lettura e scrittura?
  2. Associato a ciò: in che modo i sistemi operativi lo implementano di solito? Sembrerebbe che qualsiasi cosa dichiarata thread_local debba avere uno spazio di memoria specifico per il thread per ogni thread creato.
+3

Il costo maggiore è la manutenibilità del codice. –

risposta

8

Spazio di archiviazione: dimensione della variabile * numero di thread, o possibilmente (sizeof (var) + sizeof (var *)) * numero di thread.

Ci sono due modi fondamentali di attuazione archiviazione thread-local:

  1. utilizzando una sorta di chiamata di sistema che riceve le informazioni sul kernel thread corrente. Sloooow.

  2. Utilizzo di un puntatore, probabilmente in un registro del processore, impostato correttamente su ogni switch di contesto del thread da parte del kernel - contemporaneamente a tutti gli altri registri. A buon mercato.

Sulle piattaforme Intel, la variante 2 viene solitamente implementata tramite un registro di segmenti (FS o GS, non ricordo). Sia GCC che MSVC supportano questo. I tempi di accesso sono quindi veloci quanto le variabili globali.

È anche possibile, ma non l'ho ancora visto nella pratica, perché questo sia implementato tramite funzioni di libreria esistenti come pthread_getspecific. Le prestazioni sarebbero quindi pari a 1. o 2., più l'overhead di chiamata della libreria. Tieni presente che la variante 2 + l'overhead di chiamata della libreria è ancora molto più veloce di una chiamata al kernel.

+0

Va notato che il caricatore dell'eseguibile del sistema operativo e il linker dinamico (per librerie/DLL condivise) necessitano di un supporto specifico per Variant 2. Far funzionare TLS tramite il registro dei segmenti è un bel po 'di lavoro. Ma ne vale la pena poiché l'overhead dell'utilizzo della variabile TLS è quindi trascurabile rispetto a un normale globale. –

9

Una descrizione di come funziona su Linux di Uli Drepper (manutentore di glibc) può essere trovato qui: www.akkadia.org/drepper/tls.pdf

L'esigenza di gestire moduli caricati dinamicamente ecc rendere l'intero meccanismo un po 'complicata, che forse parzialmente spiega perché il documento pesa in 79 pagine (!).

Memoria-utilizzo-saggio, ogni variabile per-thread ha ovviamente bisogno della propria memoria per-thread (sebbene in alcuni casi questo possa essere fatto pigramente in modo tale che lo spazio venga allocato solo una volta che la variabile è stata prima consultata), e quindi ci sono alcuni dati aggiuntivi necessari per le tabelle offset ecc.

Per quanto riguarda le prestazioni, il costo aggiuntivo per accedere a una variabile TLS ruota principalmente intorno al recupero dell'indirizzo della variabile. Su x86 Linux il registro GS viene utilizzato come inizio per ottenere un ID thread, su x86-64 FS. Di solito ci sono alcuni riferimenti ai puntatori e una chiamata di funzione (__tls_get_addr) per il codice caricato dinamicamente. C'è anche il costo che la creazione di un nuovo thread è più lento perché l'implementazione deve allocare spazio e possibilmente inizializzare tutte le vele TLS (se non fatto pigramente).

TLS è utile per rendere facilmente thread-safe alcuni vecchi schemi di thread non sicuri (si pensi a errno), ma per un nuovo codice progettato dall'inizio per un mondo a più thread è molto raramente necessario.

+6

Non sono d'accordo con questo _questo commento raramente necessario. TLS è un modo molto semplice, pulito e rapido per ridurre la contesa tra thread e migliorare le prestazioni evitando ricerche ripetute in una discussione. –

Problemi correlati