Regras e limitações de TLS
As diretrizes a seguir devem ser observadas quando declarar estaticamente ligado segmento local objetos e variáveis:
O thread atributo pode ser aplicado somente a definições e declarações de dados.Ele não pode ser usado em declarações de função ou definições.Por exemplo, o código a seguir gera um erro do compilador:
#define Thread __declspec( thread ) Thread void func(); // This will generate an error.
O thread modificador pode ser especificado somente em itens de dados com static extensão.Isso inclui objetos de dados globais (ambos static e extern), locais objetos estáticos e membros de dados estáticos de classes C++.Objetos de dados automáticos não podem ser declarados com o thread atributo.O código a seguir gera erros do compilador:
#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; }
As declarações e a definição de um thread objeto local deve especificar o thread atributo.Por exemplo, o código a seguir gera um erro:
#define Thread __declspec( thread ) extern int tls_i; // This will generate an error, since the int Thread tls_i; // declaration and definition differ.
O thread atributo não pode ser usado como um modificador de tipo.Por exemplo, o código a seguir gera um erro do compilador:
char __declspec( thread ) *ch; // Error
Classes C++ não é possível usar o thread atributo.No entanto, os objetos de classe do C++ podem ser instanciados com a thread atributo.Por exemplo, o código a seguir gera um erro do compilador:
#define Thread __declspec( thread ) class Thread C // Error: classes cannot be declared Thread. { // Code }; C CObject;
Porque a declaração de C++ objetos que usam o thread atributo é permitido, dois exemplos a seguir são semanticamente equivalentes:
#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.
O endereço de um objeto local de thread não é considerado constante e qualquer expressão envolvendo um endereço não é considerada uma expressão de constante.C padrão, o efeito é proibir o uso do endereço de uma variável de segmento local como um inicializador de um objeto ou um ponteiro.Por exemplo, o código a seguir é sinalizado como um erro pelo compilador C:
#define Thread __declspec( thread ) Thread int tls_i; int *p = &tls_i; //This will generate an error in C.
Essa restrição não se aplica em C++.Porque C++ permite inicialização dinâmica de todos os objetos, você pode inicializar um objeto usando uma expressão que utiliza o endereço de uma variável de segmento local.Isso é feito exatamente como a construção de objetos de thread local.Por exemplo, o código mostrado anteriormente não gera um erro quando ele é compilado como um arquivo de origem C++.Observe que o endereço de uma variável de segmento local é válido apenas como o thread no qual o endereço foi tirado ainda existe.
C padrão permite a inicialização de um objeto ou variável com uma expressão que envolve uma referência a mesmo, mas somente para objetos de extensão não estático.Embora C++ geralmente permite tal inicialização dinâmica de objetos com uma expressão que envolve uma referência a mesmo, esse tipo de inicialização não é permitido com objetos de thread local.Por exemplo:
#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++
Observe que uma sizeof expressão inclui o objeto que está sendo inicializado não representa uma referência a mesmo e é habilitado em c e C++.
C++ não permite tal inicialização dinâmica de dados de thread devido a possíveis futuros aprimoramentos para o recurso de armazenamento local de thread.
Em sistemas operacionais do Windows antes de Windows Vista, __declspec(thread) tem algumas limitações.Se uma DLL declara quaisquer dados ou objeto como __declspec(thread), ele pode causar uma falha de proteção se carregado dinamicamente.Depois que a DLL é carregada com LoadLibrary, ele causa uma falha do sistema sempre que o código faz referência a __declspecdados (thread).Porque o espaço de variável global para um thread é alocado em tempo de execução, o tamanho desse espaço é baseado em um cálculo de requisitos do aplicativo mais requisitos de todas as DLLs vinculadas estaticamente.Quando você usa LoadLibrary, não é possível estender esse espaço para as variáveis de segmento locais declaradas com __declspec(thread).Use as APIs de TLS, como TlsAlloc, na sua DLL alocar TLS se a DLL pode ser carregada com LoadLibrary.