Regole e limitazioni per TLS
Aggiornamento: novembre 2007
Nella dichiarazione di oggetti e di variabili locali di thread associati in modo statico, è necessario attenersi alle istruzioni riportate di seguito.
L'attributo thread è applicabile solo a dichiarazioni e definizioni di dati. Non può essere utilizzato per dichiarare o definire funzioni. Il codice seguente, ad esempio, genera un errore di compilazione:
#define Thread __declspec( thread ) Thread void func(); // This will generate an error.
Il modificatore thread può essere specificato solo per elementi di dati di tipo static. Sono compresi gli oggetti di dati globali, sia static che extern, gli oggetti statici locali e i membri dati statici delle classi di C++. Non è possibile dichiarare oggetti di dati automatici con l'attributo thread. Il codice seguente genera errori di compilazione:
#define Thread __declspec( thread ) void func1() { Thread int tls_i; // This will generate an error. } int func2( Thread int tls_i ) // This will generate an error. { return tls_i; }
È necessario che nelle dichiarazioni e nella definizione di un oggetto locale rispetto al thread sia specificato l'attributo thread. Il codice seguente genera ad esempio un errore:
#define Thread __declspec( thread ) extern int tls_i; // This will generate an error, since the int Thread tls_i; // declaration and definition differ.
L'attributo thread non può essere utilizzato come modificatore di tipo. Il codice seguente, ad esempio, genera un errore di compilazione:
char __declspec( thread ) *ch; // Error
Nelle classi di C++ non può essere utilizzato l'attributo thread. È possibile tuttavia creare un'istanza di oggetti di classe C++ con l'attributo thread. Il codice seguente, ad esempio, genera un errore di compilazione:
#define Thread __declspec( thread ) class Thread C // Error: classes cannot be declared Thread. { // Code }; C CObject;
Poiché la dichiarazione di oggetti C++ che utilizzano l'attributo thread è consentita, i due esempi che seguono sono equivalenti dal punto di vista semantico:
#define Thread __declspec( thread ) Thread class B { // Code } BObject; // OK--BObject is declared thread local. class B { // Code }; Thread B BObject; // OK--BObject is declared thread local.
L'indirizzo di un oggetto locale di thread non è considerato come costante, così come qualsiasi espressione che contenga tale indirizzo. Nel linguaggio C standard l'utilizzo dell'indirizzo di una variabile locale di thread come inizializzatore di un oggetto o puntatore, di conseguenza, non è consentito. Il codice seguente, ad esempio, viene contrassegnato come errore dal compilatore C:
#define Thread __declspec( thread ) Thread int tls_i; int *p = &tls_i; //This will generate an error in C.
La restrizione, tuttavia, non si applica al linguaggio C++. Poiché C++ consente l'inizializzazione dinamica di tutti gli oggetti, è possibile inizializzare un oggetto con un'espressione che utilizza l'indirizzo di una variabile locale di thread. Questa operazione viene eseguita mediante la stessa procedura utilizzata per la costruzione degli oggetti locali di thread. Nel codice sopra riportato, ad esempio, non viene generato un errore se il codice viene compilato come file sorgente C++. Si noti che l'indirizzo di una variabile locale di thread è valido solo fino a quando il thread dal quale l'indirizzo è stato preso è esistente.
Il linguaggio C standard consente di inizializzare un oggetto o una variabile con un'espressione che include un riferimento a se stessa, ma solo per oggetti di tipo non statico. Sebbene il linguaggio C++ consenta in genere l'inizializzazione dinamica di oggetti con espressioni che includono un riferimento a se stesse, questo tipo di inizializzazione non è consentito con gli oggetti locali di thread. Esempio:
#define Thread __declspec( thread ) Thread int tls_i = tls_i; // Error in C and C++ int j = j; // OK in C++, error in C Thread int tls_i = sizeof( tls_i ) // Legal in C and C++
Si noti che un'espressione sizeof nella quale è incluso l'oggetto inizializzato non costituisce un riferimento a se stessa ed è valida sia in C che in C++.
C++ non consente questo tipo di inizializzazione dinamica dei dati di thread, in relazione a possibili miglioramenti futuri della gestione della memoria locale di thread.
Se in una DLL sono dichiarati dati o oggetti non locali come __declspec( thread ), quando viene caricata in modo dinamico, può provocare un errore di protezione. Dopo il caricamento della DLL con LoadLibrary, viene generato un errore di sistema ogni volta che il codice fa riferimento a dati di __declspec( thread ) non locali. Poiché lo spazio delle variabili globali per un thread viene assegnato in fase di esecuzione, la sua dimensione si basa sul calcolo dei requisiti dell'applicazione più i requisiti di tutte le DLL collegate in modo statico. Quando si utilizza LoadLibrary non è possibile in alcun modo estendere tale spazio per le variabili locali di thread dichiarate con __declspec( thread ). Utilizzare le API TLS, come TlsAlloc, nella DLL per l'assegnazione di TLS, se la DLL può essere caricata con LoadLibrary.