Rendere le variabili statiche globali multithread sicure
-
27-09-2019 - |
Domanda
Ho variabili statiche globali in una libreria C, che generano eccezioni in un'esecuzione multithread.Devo renderli sicuri in qualche modo (vale a dire, ogni thread dovrebbe riguardare un'istanza diversa di queste variabili).Qualche metodo consigliato?
Soluzione
Non esiste un modo standard che funzioni in tutte le implementazioni C, ma esistono soluzioni specifiche dell'implementazione. Ad esempio, con il compilatore di Microsoft (vedi i documenti),
__declspec( thread ) int tls_i = 1;
fa tls_i
Live in thread-local Storage (ogni thread ha la propria istanza separata di questa variabile). Insieme a GCC, la sintassi è
__thread int tls_i;
Potresti anche voler controllare il ingresso di Wikipedia a questo proposito.
Altri suggerimenti
Prima domanda:
- i thread necessitano delle proprie copie delle variabili?
- oppure devono coordinare l'accesso a un'unica copia condivisa?
Se hai bisogno del primo, le altre risposte hanno fornito suggerimenti sulla "archiviazione locale del thread".
Se hai bisogno di quest'ultimo, in un modo o nell'altro devi assicurarti che ci sia un mutex appropriato su quelle variabili (l'ambito del mutex è uno dei problemi che devi affrontare) e che tutti i thread utilizzino il mutex e rilascino il mutex.Questo è più complicato.Potrebbe anche essere necessario fornire funzioni che controllino l'accesso alle variabili.
La variabile standard errno
può essere un lvalue modificabile:
extern int *_errno_func(void);
#define errno (*(_errno_func)())
In un'applicazione threaded (compilata con -DREENTRANT), questo è ciò che accade;su MacOS X, sembra che ciò accada comunque (utilizzano il nome __error
invece di _errno_func
;entrambi sono nello spazio dei nomi dell'implementazione).
Potresti voler, o finire per dover, fare qualcosa di simile per le tue variabili.Il fatto che tu dica che sono statici migliora un po' le cose.Hai solo un file da gestire (a meno che tu non sia abbastanza distratto da passare indietro o attivare puntatori a quelle variabili).
Ciò di cui hai bisogno è TLS (thread Local Storage), che è anche noto come Dati specifici del thread o Dati thread-private. Questo meccanismo può garantire a ciascun thread di accedere alla propria copia separata dei dati, senza preoccuparsi di sincronizzare l'accesso con altri thread.
Esistono due metodi per utilizzare TLS:
implicito: usando la parola chiave
Finestre: __declspec (thread) int tls_var = 10;
Linux con GCC: __Thread int tls_var = 10
esplicito: usando API relativa a TLS specifica
Finestre:
- Tlsalloc (): allocare la memoria per i dati TLS
- Tlsfree (): liberare la memoria dei dati TLS
- TlssetValue (): Imposta il valore di TLS
- TlsgetValue (): Ottieni il valore di TLS
Fare riferimento a MSDN per informazioni dettagliate.
Linux con GCC:
- pThread_key_create (): Crea i dati TLS
- pThread_key_delete (): Destory i dati TLS
- pThread_getSpecific (): ottieni il valore di TLS
- pThread_setspecific(): imposta il valore di TLS
La maggior parte dei compilatori ha un modo di designare l'archiviazione dei fili locali. Supponendo che sia disponibile, è quello che vuoi.