Reguły i ograniczenia dotyczące TLS
Muszą być przestrzegane następujące wytyczne deklarowania statycznie powiązany zmiennych i obiektów lokalnych wątków:
thread Atrybut może być stosowana tylko do deklaracji danych i definicji.Nie można użyć w deklaracji funkcji lub definicji.Na przykład poniższy kod generuje błąd kompilatora:
#define Thread __declspec( thread ) Thread void func(); // This will generate an error.
thread Modyfikator mogą być określone tylko dla elementów danych z static zakresie.Dotyczy to obiektów danych globalnych (zarówno static i extern), lokalne obiekty statyczne i członkowie danych statycznych klasy języka C++.Nie można zadeklarować obiekty danych automatyczne z thread atrybut.Poniższy kod generuje błędy kompilatora:
#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; }
Deklaracje i definicji wątku lokalnego obiektu wszystkich określić thread atrybut.Na przykład poniższy kod generuje błąd:
#define Thread __declspec( thread ) extern int tls_i; // This will generate an error, since the int Thread tls_i; // declaration and definition differ.
thread Nie można użyć jako modyfikator typu atrybutu.Na przykład poniższy kod generuje błąd kompilatora:
char __declspec( thread ) *ch; // Error
Nie można użyć klasy języka C++ thread atrybut.Jednak obiekty klasy języka C++ można tworzyć wystąpienia z thread atrybut.Na przykład poniższy kod generuje błąd kompilatora:
#define Thread __declspec( thread ) class Thread C // Error: classes cannot be declared Thread. { // Code }; C CObject;
Ponieważ deklaracji C++ obiekty używające thread atrybut jest dozwolone, poniższe dwa przykłady są semantycznie równoważne:
#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.
Adres lokalny obiekt wątku nie jest uważany za stały, a wszelkie wyrażenie dotyczące takiego adresu nie jest uważane za wyrażenie stałe.W standardowych C efektem tego jest zakazującą stosowania adres zmiennej lokalnej wątku jako inicjatora do obiektu lub wskaźnik.Na przykład poniższy kod jest traktowane jako błąd przez kompilator C:
#define Thread __declspec( thread ) Thread int tls_i; int *p = &tls_i; //This will generate an error in C.
Ograniczenie to nie ma zastosowania w języku C++.Ponieważ C++ pozwala na dynamiczne inicjowania wszystkich obiektów, można zainicjować obiektu za pomocą wyrażenia, która używa adresu zmiennej lokalnej wątku.Można to osiągnąć, podobnie jak budowa obiektów lokalnych wątków.Na przykład kodu przedstawionym wcześniej nie generuje błąd podczas jest skompilowany jako pliku źródłowego języka C++.Należy zauważyć, że adres zmiennej lokalnej wątku jest ważne tylko tak długo, jak długo wątku, w którym została podjęta adres nadal istnieje.
Standardowy C pozwala na zainicjowanie obiektu lub zmienna o wyrażenie obejmujących odwołanie do samej siebie, ale tylko w przypadku obiektów o zakresie niestatycznego.Chociaż C++ zazwyczaj umożliwia takie dynamicznego inicjowania obiektów z wyrażenie obejmujących odwołanie do samej siebie, tego rodzaju inicjowanie nie jest dozwolone z wątku lokalnych obiektów.Na przykład:
#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++
Należy zauważyć, że sizeof wyrażenia zawierającego obiekt jest inicjowany nie stanowi odwołanie do samej siebie i jest włączona w C i C++.
C++ nie zezwala na takie dynamicznego inicjowania wątku danych z powodu możliwych przyszłych rozszerzeń do obiektu lokalnego magazynu wątków.
W systemach operacyjnych Windows przed Windows Vista, __declspec(wątek) ma pewne ograniczenia.Jeżeli biblioteka DLL deklaruje żadnych danych ani obiektów jako __declspec(wątku), może to spowodować błąd ochrony Jeśli ładowany dynamicznie osobno.Po załadowaniu biblioteki DLL z LoadLibrary, powoduje awarii systemu, w każdym przypadku, gdy odwołuje się kod __declspecdanych (wątku).Ponieważ przestrzeni zmiennej globalnej dla wątku jest przydzielane w czasie wykonywania, rozmiar tego miejsca jest oparty na obliczenie wymagań aplikacji oraz wymagań wszystkich bibliotek DLL, które są statycznie połączone.Użycie LoadLibrary, nie można rozszerzyć tego miejsca, aby umożliwić wątku zmiennych lokalnych zadeklarowanych za pomocą __declspec(wątku).Przy użyciu interfejsów API TLS, takie jak TlsAlloc, w bibliotece DLL przydzielić TLS, jeśli biblioteka DLL jest obciążany LoadLibrary.