Partilhar via


Armazenamento Local de Thread (TLS)

Thread Local Storage (TLS) é o método pelo qual cada thread em um determinado processo multithreaded pode alocar locais nos quais armazenar dados específicos do thread. Os dados específicos de thread, ligados dinamicamente em tempo de execução, são suportados por meio da API TLS (TlsAlloc). Win32 e o compilador Microsoft C++ agora suportam dados ligados estaticamente (tempo de carregamento) por thread, além da implementação de API existente.

Implementação do compilador para TLS

C++11: O thread_local especificador de classe de armazenamento é a maneira recomendada de especificar o armazenamento local de thread para objetos e membros de classe. Para obter mais informações, consulte Classes de armazenamento (C++).

O MSVC também fornece um atributo específico da Microsoft, thread, como modificador de classe de armazenamento estendido. Use a __declspec palavra-chave para declarar uma thread variável. Por exemplo, o código a seguir declara uma variável local de thread inteiro e a inicializa com um valor:

__declspec( thread ) int tls_i = 1;

Regras e limitações

As diretrizes a seguir devem ser observadas ao declarar objetos e variáveis locais de thread ligados estaticamente. Estas diretrizes aplicam-se tanto ao thread como ao thread_local:

  • O thread atributo pode ser aplicado somente a declarações e definições de classe e dados. Ele não pode ser usado em declarações ou definições de função. Por exemplo, o código a seguir gera um erro de compilador:

    __declspec( thread )void func();     // This will generate an error.
    
  • O thread modificador só pode ser especificado em itens de dados com static extensão. Isso inclui objetos de dados globais (ambos static e extern), objetos estáticos locais e membros de dados estáticos de classes C++. Os objetos de dados automáticos não podem ser declarados com o thread atributo. O código a seguir gera erros do compilador:

    void func1()
    {
        __declspec( thread )int tls_i;            // This will generate an error.
    }
    
    int func2(__declspec( thread )int tls_i )     // This will generate an error.
    {
        return tls_i;
    }
    
  • As declarações e a definição de um objeto local de thread devem 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 __declspec( 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 de compilador:

    char __declspec( thread ) *ch;        // Error
    
  • Como a declaração de objetos C++ que usam o thread atributo é permitida, os dois exemplos a seguir são semanticamente equivalentes:

    __declspec( thread ) class B
    {
    // Code
    } BObject;  // OK--BObject is declared thread local.
    
    class B
    {
    // Code
    };
    __declspec( 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 tal endereço não é considerada uma expressão constante. No padrão C, o efeito é proibir o uso do endereço de uma variável local de thread como inicializador para um objeto ou ponteiro. Por exemplo, o código a seguir é sinalizado como um erro pelo compilador C:

    __declspec( thread ) int tls_i;
    int *p = &tls_i;       //This will generate an error in C.
    

    Essa restrição não se aplica em C++. Como o C++ permite a inicialização dinâmica de todos os objetos, você pode inicializar um objeto usando uma expressão que usa o endereço de uma variável local de thread. É feito como a construção de objetos locais de thread. Por exemplo, o código mostrado anteriormente não gera um erro quando é compilado como um arquivo de origem C++. O endereço de uma variável local de thread é válido apenas enquanto o thread no qual o endereço foi obtido ainda existir.

  • O padrão C permite a inicialização de um objeto ou variável com uma expressão que envolve uma referência a si mesma, mas apenas para objetos de extensão não estática. Embora o C++ geralmente permita essa inicialização dinâmica de objetos com uma expressão que envolve uma referência a si mesmo, esse tipo de inicialização não é permitido com objetos locais de thread. Por exemplo:

    __declspec( thread )int tls_i = tls_i;                // Error in C and C++
    int j = j;                               // OK in C++, error in C
    __declspec( thread )int tls_i = sizeof( tls_i )       // Legal in C and C++
    

    Uma sizeof expressão que inclui o objeto que está sendo inicializado não representa uma referência a si mesma e está habilitada em C e C++.

    O C++ não permite essa inicialização dinâmica de dados de thread devido a possíveis aprimoramentos futuros no recurso de armazenamento local de thread.

  • Em sistemas operacionais Windows antes do Windows Vista, __declspec( thread ) tem algumas limitações. Se uma DLL declarar qualquer dado ou objeto como __declspec( thread ), ela poderá causar uma falha de proteção se carregada dinamicamente. Depois que a DLL é carregada com LoadLibrary, ela causa falha do sistema sempre que o código faz referência aos __declspec( thread ) dados. Como o espaço variável global para um thread é alocado em tempo de execução, o tamanho desse espaço é baseado em um cálculo dos requisitos do aplicativo mais os requisitos de todas as DLLs que estão vinculadas estaticamente. Quando usas LoadLibrary, não é possível estender este espaço para permitir as variáveis locais da thread declaradas com __declspec( thread ). Utilize as APIs TLS, como TlsAlloc, na sua DLL para alocar TLS caso a DLL possa ser carregada com LoadLibrary.

Ver também

Multithreading com C e Win32