Thread Local Storage

Thread Local Storage

Le Thread Local Storage (TLS), ou mémoire locale de thread, est un type de mémoire spécifique et locale à un thread.

Ce mécanisme est parfois requis parce que tous les threads d'un même processus partagent le même espace d'adressage. Donc, les données situées dans une variable statique ou globale sont exactement au même emplacement mémoire pour tous les threads, et correspondent donc à la même entité.

Les variables sur la pile sont toutefois locales au thread, parce que chaque thread possède sa propre pile, distincte de celle des autres threads.

Cependant, il est parfois utile que deux threads puissent référencer la même variable « globale » tout en possédant chacun une copie distincte, donc à des adresses mémoire différentes. Ceci rend la variable « locale » au thread, tout en ayant une syntaxe d'utilisation identique à celle d'une variable globale. Un exemple trivial d'une telle variable est, par exemple, la variable errno du langage C.

S'il est possible de rendre au minimum un pointeur local aux threads, alors il est possible de créer pour chaque thread du système une zone mémoire de taille arbitraire contenant des données locales de thread. En effet, cette zone peut elle-même être un simple tableau de pointeurs, ce qui permet ensuite (par déréférencements successifs) d'obtenir un TLS de taille totalement arbitraire, quelle que soit la limite initiale de la zone.

Sommaire

Illustration

Principle générique du TLS

Le processus possède ici deux threads. On alloue deux slots du TLS : le premier pour stocker un entier (index 2), le second pour stocker un pointeur (index 4), en bleu clair. Chaque thread va alors obtenir une zone mémoire privée (parties vert sombre pour le thread 1, bleu sombre pour le thread 2), permettant d'accéder à sa donnée locale, éventuellement via une indirection pour le pointeur, tout en n'utilisant qu'un index global et identique entre les deux (simplification du code).

Implémentations dépendantes du système d'exploitation

Implémentation sous Windows

Dans l'API Windows[1], on utilise le terme TLS.

La fonction TlsAlloc est utilisée pour obtenir un index de slot TLS inutilisé - en pratique, le premier disponible - qui sera ensuite réservé jusqu'à la fin du processus ou la libération du TLS. Un seul thread doit appeler cette fonction : par la suite, seul l'index retourné est utilisé. Cette opération est bien entendu totalement atomique. On fournit en général ensuite cet index aux threads soit via une variable globale (accédée en lecture seule par les threads), soit dans les paramètres de création du thread (solution préférable). L'index retourné est un entier, mais ne doit pas être considéré comme un indice de tableau. Il est nécessaire de le traiter comme un type opaque.

Les fonctions TlsGetValue et TlsSetValue sont ensuite utilisées pour (respectivement) lire et écrire une variable TLS, identifiée par son index de slot TLS. Cette variable est un pointeur non-typé, dont l'usage est libre, et qui sera propre à chaque thread. Toutefois, tout thread est responsable de l'allocation des données ciblées par ce pointeur.
On peut noter que la taille de ce pointeur est dépendante de l'architecture Windows courante (32 bits ou 64 bits), et qu'il n'est pas contre-indiqué d'utiliser le slot pour stocker une variable quelconque, de taille inférieure ou égale à celle du pointeur, en lieu et place d'un pointeur.
Ceci recouvre notamment le cas d'un entier : c'est ainsi que l'API Windows stocke le dernier code d'erreur obtenu par GetLastError, par exemple.

La fonction TlsFree peut être utilisée pour libérer l'index de slot TLS passé en paramètre. L'index est ensuite considéré de nouveau comme « inutilisé », et pourra être réattribué par la suite. Il est donc crucial d'être certain, lors de la libération, qu'il n'existe plus aucun thread utilisant cet index TLS.

Implémentation sous Pthreads (Linux)

Dans l'API Pthreads[2], on utilise le terme TSD (Thread-Specific Data) pour désigner le TLS.

Le principe est similaire à celui utilisé sous Windows, seuls les noms des fonctions changent :

  1. pthread_key_create est équivalent à TlsAlloc.
  2. pthread_getspecific est équivalent à TlsGetValue.
  3. pthread_setspecific est équivalent à TlsSetValue.
  4. pthread_key_delete est équivalent à TlsFree.
  5. La clé (key) est équivalent à l'index de slot TLS, mais est définie via un type explicitement opaque pthread_key_t.

La seule différence réelle entre les deux systèmes est que pthread_key_create permet de définir un destructeur optionnel qui sera appelé automatiquement à la fin du thread. Chaque destructeur recevra, en paramètre, le contenu stocké dans la clé associée, permettant ainsi d'effectuer la libération des ressources associées.

L'utilisation de ce destructeur ne dispense pas d'appeler explicitement pthread_key_delete pour libérer le TSD lui-même, au niveau du processus. Le destructeur ne permet que la libération des données locales au thread.

Implémentations spécifiques

En plus de la possibilité d'appeler les fonctions natives du système d'exploitation décrites ci-dessus, certains langages ou compilateurs permettent d'utiliser une fonctionnalité équivalente, voire identique, au TLS de façon plus simple et/ou plus pratique que faire appel aux primitives système.

Compilateurs et IDE

Visual C++ et Intel C++ Compiler (Windows)

Le mot-clé __declspec(thread) est utilisé en préfixe de déclaration :

    int variable_globale;
    __declspec(thread) int variable_TLS ;

La variable TLS est ensuite utilisable de façon tout à fait normale.

Sun Studio, IBM XL C/C++ et Intel C++ Compiler (Linux)

Le mot-clé __thread est utilisé en préfixe de déclaration :

    int variable_globale ;
    __thread int variable_TLS ;

La variable TLS est ensuite utilisable de façon tout à fait normale.

Digital Mars C++

Le mot-clé __declspec(thread) est utilisé en préfixe de déclaration :

    int variable_globale ;
    __declspec(thread) int variable_TLS ;

La variable TLS est ensuite utilisable de façon tout à fait normale.

Borland C++ Builder (Windows)

Le mot-clé __declspec(thread) est utilisé en préfixe de déclaration :

    int variable_globale  ;
    __declspec(thread) int variable_TLS ;

Le mot-clé __thread est une alternative de déclaration, mais entre le type et l'identifiant :

    int variable_globale  ;
    int __thread variable_TLS ;

Dans les deux cas, la variable TLS est ensuite utilisable de façon tout à fait normale.

GCC/G++

Le mot-clé __thread est utilisé en préfixe de déclaration, mais est implémenté de façon particulière :

    int variable_globale  ;
    __thread int variable_TLS = 1 ;

Toutefois, la variable TLS doit impérativement être initialisée avec une constante connue au moment de la compilation (cas de l'exemple ci-dessus).

Il n'est pas autorisé de déclarer une variable TLS sans initialisation, ou étant initialisée par un paramètre et/ou un appel de fonction.

Langages

Delphi et Free Pascal

Le mot-clé ThreadVar est utilisé en lieu et place du traditionnel Var pour déclarer une variable TLS.

    Var
        variable_globale : Integer ;
    ThreadVar
        variable_TLS : Integer ;

La variable TLS est ensuite utilisable de façon tout à fait normale.

Java

En Java, les variables TLS sont implémentées au travers de la classe ThreadLocal (en). Un objet ThreadLocal maintient une instance séparée de la variable pour chaque thread appelant les accesseurs de l'objet (get et set).

L'exemple ci-dessous montre comment créer une variable entière TLS :

    ThreadLocal<Integer> variable_TLS = new ThreadLocal<Integer>() {
        @Override protected Integer initialValue() {
            return 1;
        }
    } ;

L'utilisation de la variable se fait au travers des accesseurs. Par exemple, une incrémentation :

    variable_TLS.set( variable_TLS.get() + 1 ) ;

D

En D (version 2), toutes les variables statiques et globales sont, par défaut, locales aux threads et sont déclarées comme les variables « normales » des autres langages. C'est la déclaration explicite d'une variable globale « partagée » qui requiert l'utilisation d'un mot-clé spécifique, __gshared.

    int variable_TLS ;
    __gshared int variable_globale  ;

La variable TLS est ensuite utilisable de façon tout à fait normale, ainsi que la variable globale déclarée explicitement.

C# et langages .NET

On utilise l'attribut ThreadStatic (en) :

    class classe_avec_TLS {
        [ThreadStatic] static int variable_TLS ;
    }

Également, on peut allouer dynamiquement des variables TLS via l'API Thread.GetNamedDataSlot (en).

La variable TLS est ensuite utilisable de façon tout à fait normale.

Python

En Python (version 2.4 ou supérieure), on utilise la classe local du module threading pour définir une variable TLS.

    import threading
    variable_TLS = threading.local()
    variable_TLS.x = 1

La variable TLS est ensuite utilisable de façon tout à fait normale.

Ruby

En Ruby, une variable TLS est créée et utilisée grâce aux méthodes []=/[].

    Thread.current[:index_TLS] = 1

Perl

Le support des threads n'est arrivé que tardivement dans le langage Perl, après qu'une vaste quantité de code source fut présente sur Comprehensive Perl archive network. En conséquence de ceci, les threads en Perl créent par défaut leur propre TLS pour toutes les variables, de façon à minimiser l'impact des threads sur le code existant non thread-safe. En Perl, une variable partagée entre les threads (cas « normal » dans les autres langages) est créée en utilisant un attribut :

    use threads;
    use threads::shared;
 
    my $variable_TLS;
    my $variable_globale  :shared;

Liens externes

Références



Wikimedia Foundation. 2010.

Contenu soumis à la licence CC-BY-SA. Source : Article Thread Local Storage de Wikipédia en français (auteurs)

Игры ⚽ Поможем сделать НИР

Regardez d'autres dictionnaires:

  • Thread-local storage — (TLS) is a computer programming method that uses static or global memory local to a thread.This is sometimes needed because all threads in a process share the same address space.In other words, data in a static or global variable is normally… …   Wikipedia

  • Thread safety — is a computer programming concept applicable in the context of multi threaded programs. A piece of code is thread safe if it functions correctly during simultaneous execution by multiple threads. In particular, it must satisfy the need for… …   Wikipedia

  • Thread (informatique) — Pour les articles homonymes, voir Thread et Fil. Un processus avec deux threads. Un thread ou fil (d exécution) o …   Wikipédia en Français

  • Thread (Informatik) — Ein Thread (auch: Aktivitätsträger oder leichtgewichtiger Prozess) bezeichnet in der Informatik einen Ausführungsstrang oder eine Ausführungsreihenfolge in der Abarbeitung eines Programms. Ein Thread ist Teil eines Prozesses. Man unterscheidet… …   Deutsch Wikipedia

  • Thread (computer science) — This article is about the concurrency concept. For the multithreading in hardware, see Multithreading (computer architecture). For the form of code consisting entirely of subroutine calls, see Threaded code. For other uses, see Thread… …   Wikipedia

  • Win32 Thread Information Block — Esta página o sección está siendo traducida del idioma inglés a partir del artículo Win32 Thread Information Block, razón por la cual puede haber lagunas de contenidos, errores sintácticos o escritos sin traducir. Puedes colaborar con… …   Wikipedia Español

  • Win32 Thread Information Block — In computing, the Win32 Thread Information Block (TIB) is a data structure in Win32 on x86 that stores info about the currently running thread.The TIB is officially undocumented for Windows 9x. The Windows NT series DDK includes a struct NT TIB… …   Wikipedia

  • Kernel Thread — Ein Thread (auch: Aktivitätsträger oder leichtgewichtiger Prozess, vereinzelt auch: Faden) bezeichnet in der Informatik einen Ausführungsstrang oder eine Ausführungsreihenfolge in der Abarbeitung eines Programms. Ein Thread ist Teil eines… …   Deutsch Wikipedia

  • C++11 — C++11, also formerly known as C++0x,[1] is the name of the most recent iteration of the C++ programming language, replacing C++TR1, approved by the ISO as of 12 August 2011.[2] The name is derived from the tradition of naming language versions by …   Wikipedia

  • C++0x — is the planned new standard for the C++ programming language. It is intended to replace the existing C++ standard, ISO/IEC 14882, which was published in 1998 and updated in 2003. These predecessors are informally known as C++98 and C++03. The new …   Wikipedia

Share the article and excerpts

Direct link
Do a right-click on the link above
and select “Copy Link”