Thread local storage windows

From Wikipedia, the free encyclopedia

In computer programming, thread-local storage (TLS) is a memory management method that uses static or global memory local to a thread. The concept allows storage of data that appears to be global in a system with separate threads.

Many systems impose restrictions on the size of the thread-local memory block, in fact often rather tight limits. On the other hand, if a system can provide at least a memory address (pointer) sized variable thread-local, then this allows the use of arbitrarily sized memory blocks in a thread-local manner, by allocating such a memory block dynamically and storing the memory address of that block in the thread-local variable. On RISC machines, the calling convention often reserves a thread pointer register for this use.

While the use of global variables is generally discouraged in modern programming, some older operating systems such as UNIX were originally designed for uniprocessor hardware and often use global variables to store important values. An example is the errno used by many functions of the C library. On a modern machine, where multiple threads may be modifying the errno variable, a call of a system function on one thread may overwrite the value previously set by a call of a system function on a different thread, possibly before following code on that different thread could check for the error condition. The solution is to have errno be a variable that looks as if it is global, but is physically stored in a per-thread memory pool, the thread-local storage.

A second use case would be multiple threads accumulating information into a global variable. To avoid a race condition, every access to this global variable would have to be protected by a mutex. Instead, each thread might accumulate into a thread-local variable, thereby eliminating any possibility of a race condition, thereby removing the need for locking. The threads then only have to synchronise a final accumulation from their own thread-local variable into a single global variable.

Windows implementation

[edit]

The application programming interface (API) function TlsAlloc can be used to obtain an unused TLS slot index; the TLS slot index will then be considered ‘used’.

The TlsGetValue and TlsSetValue functions are then used to read and write a memory address to a thread-local variable identified by the TLS slot index. TlsSetValue only affects the variable for the current thread. The TlsFree function can be called to release the TLS slot index.

There is a Win32 Thread Information Block for each thread. One of the entries in this block is the thread-local storage table for that thread.[1]
Each call of TlsAlloc returns a unique index into this table. Each thread can independently use TlsSetValue(index, value) and obtain the specified value via TlsGetValue(index), because these set and look up an entry in the thread’s own table.

Apart from TlsXxx function family, Windows executables can define a section which is mapped to a different page for each thread of the executing process. Unlike TlsXxx values, these pages can contain arbitrary and valid addresses. These addresses, however, are different for each executing thread and therefore should not be passed to asynchronous functions (which may execute in a different thread) or otherwise passed to code which assume that a virtual address is unique within the whole process. TLS sections are managed using memory paging and its size is quantized to a page size (4kB on x86 machines).
Such sections may only be defined inside a main executable of a program — DLLs should not contain such sections, because they are not correctly initialized when loading with LoadLibrary.

Pthreads implementation

[edit]

In the Pthreads API, memory local to a thread is designated with the term Thread-specific data.

The functions pthread_key_create and pthread_key_delete are used respectively to create and delete a key for thread-specific data. The type of the key is explicitly left opaque and is referred to as pthread_key_t. This key can be seen by all threads. In each thread, the key can be associated with thread-specific data via pthread_setspecific. The data can later be retrieved using pthread_getspecific.

In addition pthread_key_create can optionally accept a destructor function that will automatically be called at thread exit, if the thread-specific data is not NULL. The destructor receives the value associated with the key as parameter so it can perform cleanup actions (close connections, free memory, etc.). Even when a destructor is specified, the program must still call pthread_key_delete to free the thread-specific data at process level (the destructor only frees the data local to the thread).

Language-specific implementation

[edit]

Apart from relying on programmers to call the appropriate API functions, it is also possible to extend the programming language to support thread local storage (TLS).

In C11, the keyword _Thread_local is used for defining thread-local variables. The header <threads.h>, if supported, defines thread_local as a synonym for that keyword. Example usage:

#include <threads.h>
thread_local int foo = 0;

In C11, <threads.h> also defines a number of functions for retrieving, changing, and destructing a thread-local storage, using names starting with tss_. In C23, thread_local itself becomes a keyword.[2]

C++11 introduces the thread_local[3] keyword which can be used in the following cases

  • Namespace level (global) variables
  • File static variables
  • Function static variables
  • Static member variables

Aside from that, various compiler implementations provide specific ways to declare thread-local variables:

  • Solaris Studio C/C++,[4] IBM XL C/C++,[5] GNU C,[6] llvm-gcc,[7] Clang,[8] and Intel C++ Compiler (Linux systems)[9] use the syntax:
    __thread int number;
  • Visual C++,[10] Intel C/C++ (Windows systems),[11] C++Builder, Clang,[12] and Digital Mars C++ use the syntax:
    __declspec(thread) int number;
  • C++Builder also supports the syntax:
    int __thread number;

On Windows versions before Vista and Server 2008, __declspec(thread) works in DLLs only when those DLLs are bound to the executable, and will not work for those loaded with LoadLibrary() (a protection fault or data corruption may occur).[10]

Common Lisp and other dialects

[edit]

Common Lisp provides a feature called dynamically scoped variables.

Dynamic variables have a binding which is private to the invocation of a function and all of the children called by that function.

This abstraction naturally maps to thread-specific storage, and Lisp implementations that provide threads do this. Common Lisp has numerous standard dynamic variables, and so threads cannot be sensibly added to an implementation of the language without these variables having thread-local semantics in dynamic binding.

For instance the standard variable *print-base* determines the default radix in which integers are printed. If this variable is overridden, then all enclosing code will print integers in an alternate radix:

;;; function foo and its children will print
;; in hexadecimal:
(let ((*print-base* 16)) (foo))

If functions can execute concurrently on different threads, this binding has to be properly thread-local, otherwise each thread will fight over who controls a global printing radix.

In D version 2, all static and global variables are thread-local by default and are declared with syntax similar to «normal» global and static variables in other languages. Global variables must be explicitly requested using the shared keyword:

int threadLocal;  // This is a thread-local variable.
shared int global;  // This is a global variable shared with all threads.

The shared keyword works both as the storage class, and as a type qualifier – shared variables are subject to some restrictions which statically enforce data integrity.[13] To declare a «classic» global variable without these restrictions, the unsafe __gshared keyword must be used:[14]

__gshared int global;  // This is a plain old global variable.

In Java, thread-local variables are implemented by the ThreadLocal class object.[15] ThreadLocal holds variable of type T,[15] which is accessible via get/set methods. For example, ThreadLocal variable holding Integer value looks like this:

private static final ThreadLocal<Integer> myThreadLocalInteger = new ThreadLocal<Integer>();

At least for Oracle/OpenJDK, this does not use native thread-local storage in spite of OS threads being used for other aspects of Java threading. Instead, each Thread object stores a (non-thread-safe) map of ThreadLocal objects to their values (as opposed to each ThreadLocal having a map of Thread objects to values and incurring a performance overhead).[16]

.NET languages: C# and others

[edit]

In .NET Framework languages such as C#, static fields can be marked with the ThreadStatic attribute:[17]: 898 

class FooBar
{
    [ThreadStatic]
    private static int _foo;
}

In .NET Framework 4.0 the System.Threading.ThreadLocal<T> class is available for allocating and lazily loading thread-local variables.[17]: 899 

class FooBar
{
    private static System.Threading.ThreadLocal<int> _foo;
}

Also an API is available for dynamically allocating thread-local variables.[17]: 899–890 

In Object Pascal (Delphi) or Free Pascal the threadvar reserved keyword can be used instead of ‘var’ to declare variables using the thread-local storage.

var
   mydata_process: integer;
threadvar
   mydata_threadlocal: integer;

In Cocoa, GNUstep, and OpenStep, each NSThread object has a thread-local dictionary that can be accessed through the thread’s threadDictionary method.

NSMutableDictionary *dict = [[NSThread currentThread] threadDictionary];
dict[@"A key"] = @"Some data";

In Perl threads were added late in the evolution of the language, after a large body of extant code was already present on the Comprehensive Perl Archive Network (CPAN). Thus, threads in Perl by default take their own local storage for all variables, to minimise the impact of threads on extant non-thread-aware code. In Perl, a thread-shared variable can be created using an attribute:

use threads;
use threads::shared;

my $localvar;
my $sharedvar :shared;

In PureBasic thread variables are declared with the keyword Threaded.

Threaded Var

In Python version 2.4 or later, local class in threading module can be used to create thread-local storage.

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

Multiple instances of local class can be created to store different sets of variables.[18] Thus, it is not a singleton.

Ruby can create/access thread-local variables using []=/[] methods:

Thread.current[:user_id] = 1

Thread-local variables can be created in Rust using the thread_local! macro provided by the Rust standard library:

use std::cell::RefCell;
use std::thread;

thread_local!(static FOO: RefCell<u32> = RefCell::new(1));

FOO.with(|f| {
    assert_eq!(*f.borrow(), 1);
    *f.borrow_mut() = 2;
});

// each thread starts out with the initial value of 1, even though this thread already changed its copy of the thread local value to 2
let t = thread::spawn(move || {
    FOO.with(|f| {
        assert_eq!(*f.borrow(), 1);
        *f.borrow_mut() = 3;
    });
});

// wait for the thread to complete and bail out on panic
t.join().unwrap();

// original thread retains the original value of 2 despite the child thread changing the value to 3 for that thread
FOO.with(|f| {
    assert_eq!(*f.borrow(), 2);
});
  • OpenMP — Another shared-memory multiprocessing facility which supports per-thread storage via «Data sharing attribute clauses» (see under §Clauses)
  1. ^ Pietrek, Matt (May 2006). «Under the Hood». Microsoft Systems Journal. 11 (5). Archived from the original on 9 September 2010. Retrieved 6 April 2010.
  2. ^ «Concurrency support library — cppreference.com». en.cppreference.com.
  3. ^ Section 3.7.2 in C++11 standard
  4. ^ «C-Compiler Information Specific to Sun’s Implementation». C User’s Guide Sun Studio 8. 2004. 2.3 Thread Local Storage Specifier.
  5. ^ «XL C/C++ compilers». August 2010. Thread-local storage (TLS). Archived from the original on 11 April 2011.
  6. ^ «Thread-Local Storage». GCC 3.3.1 Manual. 2003.
  7. ^ «LLVM 2.0 Release Notes». 23 May 2007. llvm-gcc Improvements.
  8. ^ «Clang Language Extensions — Clang 3.8 documentation». Introduction. This document describes the language extensions provided by Clang. In addition to the language extensions listed here, Clang aims to support a broad range of GCC extensions. Please see the GCC manual for more information on these extensions.
  9. ^ «Intel® C++ Compiler 8.1 for Linux Release Notes For Intel IA-32 and Itanium® Processors» (PDF). 2004. Thread-local Storage. Archived from the original (PDF) on 19 January 2015.
  10. ^ a b Visual Studio 2003: «Thread Local Storage (TLS)». Microsoft Docs. 5 June 2017.
  11. ^ Intel C++ Compiler 10.0 (windows): Thread-local storage
  12. ^ «Attributes in Clang — Clang 3.8 documentation». thread.
  13. ^ Alexandrescu, Andrei (6 July 2010). «Chapter 13 — Concurrency». The D Programming Language. InformIT. p. 3. Retrieved 3 January 2014.
  14. ^ Bright, Walter (12 May 2009). «Migrating to Shared». dlang.org. Retrieved 3 January 2014.
  15. ^ a b Bloch 2018, p. 151-155, §Item 33: Consider typesafe heterogeneous containers.
  16. ^ «How is Java’s ThreadLocal implemented under the hood?». Stack Overflow. Stack Exchange. Retrieved 27 December 2015.
  17. ^ a b c Albahari 2022.
  18. ^ «cpython/Lib/_threading_local.py at 3.12 · python/cpython». GitHub. Retrieved 25 October 2023.
  • Albahari, Joseph (2022). C# 10 in a Nutshell (First ed.). O’Reilly. ISBN 978-1-098-12195-2.
  • Bloch, Joshua (2018). «Effective Java: Programming Language Guide» (third ed.). Addison-Wesley. ISBN 978-0134685991.
  • ELF Handling For Thread-Local Storage — Document about an implementation in C or C++.
  • ACE_TSS< TYPE > Class Template Reference
  • RWTThreadLocal<Type> Class Template Documentation
  • Article «Use thread-local Storage to Pass Thread Specific Data» by Doug Doedens
  • «Thread-Local Storage» by Lawrence Crowl
  • Article «It’s Not Always Nice To Share» by Walter Bright
  • Practical ThreadLocal usage in Java: http://www.captechconsulting.com/blogs/a-persistence-pattern-using-threadlocal-and-ejb-interceptors
  • GCC «[1]»
  • Rust «[2]»

Provide feedback

Saved searches

Use saved searches to filter your results more quickly

Sign up

Appearance settings

Thread Local Storage ( TLS ) или память локального потока , представляет собой тип памяти специфического и локального в потоке .

Этот механизм иногда требуется, потому что все потоки в одном процессе используют одно и то же адресное пространство . Следовательно, данные, расположенные в статической или глобальной переменной, находятся в одном и том же месте памяти для всех потоков и, следовательно, соответствуют одному и тому же объекту.

Однако переменные в стеке являются локальными для потока, потому что каждый поток имеет свой собственный стек, отдельный от других потоков.

Однако иногда бывает полезно, чтобы два потока имели возможность ссылаться на одну и ту же «глобальную» переменную, в то время как каждый из них имеет отдельную копию, поэтому по разным адресам памяти. Это делает переменную «локальной» для потока, имея при этом синтаксис использования, идентичный синтаксису глобальной переменной. Тривиальный пример такой переменной, например, переменная errnoв языке Си .

Если возможно сделать хотя бы один локальный указатель потока, то можно создать для каждого потока системы область памяти произвольного размера, содержащую данные локального потока. В самом деле, эта зона сама может быть простым массивом указателей, который затем позволяет (путем последовательного разыменования) получить TLS совершенно произвольного размера, независимо от начального предела зоны.

Рисунок

Здесь процесс состоит из двух потоков. Мы выделяем два слота TLS: первый для хранения целого числа (индекс 2), второй для хранения указателя (индекс 4), выделенный голубым цветом. Затем каждый поток получит частную область памяти (темно-зеленые части для потока 1, темно-синие для потока 2), разрешая доступ к его локальным данным, возможно, через косвенный указатель для указателя, используя только глобальный и идентичный индекс между двумя (упрощение кода).

Реализации, зависящие от операционной системы

Реализация в Windows

В Windows API используется термин TLS .

TlsAlloc функция используется для получения неиспользуемого индекса слота TLS — на практике первой доступный — который будет затем быть зарезервирован до конца процесса или освобождения TLS . Только один поток должен вызывать эту функцию: после этого используется только возвращенный индекс. Эта операция, конечно, полностью атомарна. Этот индекс обычно затем предоставляется потокам либо через глобальную переменную (доступ потоков только для чтения), либо в параметрах создания потока (предпочтительное решение). Возвращаемый индекс является целым числом, но его не следует рассматривать как индекс массива. К нему нужно относиться как к непрозрачному типу .

Затем функции TlsGetValue и TlsSetValue используются для (соответственно) чтения и записи переменной TLS , идентифицируемой по ее индексу слота TLS . Эта переменная представляет собой нетипизированный указатель, который можно использовать бесплатно и который будет специфичным для каждого потока. Однако любой поток отвечает за выделение данных, на которые указывает этот указатель.
Можно отметить, что размер этого указателя зависит от текущей архитектуры Windows ( 32 бита или 64 бита ), и что не противопоказано использовать слот для хранения любой переменной меньшего размера или равного размеру указателя. вместо указателя.
Это касается, в частности, случая целого числа: так Windows API сохраняет, например, последний код ошибки, полученный GetLastError .

Функцию TlsFree можно использовать для освобождения индекса слота TLS, переданного в качестве параметра. После этого индекс снова считается «неиспользуемым» и может быть переназначен позже. Поэтому при освобождении крайне важно убедиться, что больше нет потоков, использующих этот индекс TLS .

Реализация под Pthreads (Linux)

В API Pthreads термин TSD ( данные для потока ) используется для обозначения TLS .

Принцип аналогичен тому, что используется в Windows, меняются только названия функций:

  1. pthread_key_create эквивалентен TlsAlloc .
  2. pthread_getspecific эквивалентен TlsGetValue .
  3. pthread_setspecific эквивалентен TlsSetValue .
  4. pthread_key_delete эквивалентен TlsFree .
  5. Ключ ( ключ ) эквивалентно слот индекс TLS , но определяется явным образом с помощью типа непрозрачной pthread_key_t .

Единственное реальное различие между двумя системами заключается в том, что pthread_key_create позволяет определить дополнительный деструктор, который будет вызываться автоматически в конце потока. Каждый деструктор получит в качестве параметра содержимое, хранящееся в связанном ключе, что позволит освободить связанные ресурсы.

Использование этого деструктора не устраняет необходимости явно вызывать pthread_key_delete для освобождения самого TSD на уровне процесса. Деструктор позволяет освобождать только локальные для потока данные.

Конкретные реализации

В дополнение к возможности вызова собственных функций операционной системы, описанной выше, определенные языки или компиляторы позволяют использовать функциональность, эквивалентную или даже идентичную TLS, более простым и / или более практичным способом, чем вызов системных примитивов. .

Компиляторы и IDE

Компилятор Visual C ++ и Intel C ++ (Windows)

Ключевое слово __declspec (резьба) используется в префиксе заявление:

    int variable_globale;
    __declspec(thread) int variable_TLS ;

Затем переменную TLS можно использовать совершенно обычным образом.

Sun Studio , IBM XL C / C ++ и компилятор Intel C ++ (Linux)

Ключевое слово __thread используется как префикс объявления:

    int variable_globale ;
    __thread int variable_TLS ;

Затем переменную TLS можно использовать совершенно обычным образом.

Цифровой Марс C ++

__Declspec (резьба) Ключевое слово используется в качестве префикса декларации:

    int variable_globale ;
    __declspec(thread) int variable_TLS ;

Затем переменную TLS можно использовать совершенно обычным образом.

Borland C ++ Builder (Windows)

__Declspec (резьба) Ключевое слово используется в качестве префикса декларации:

    int variable_globale  ;
    __declspec(thread) int variable_TLS ;

Ключевое слово __thread является альтернативным объявлением, но между типом и идентификатором:

    int variable_globale  ;
    int __thread variable_TLS ;

В обоих случаях переменную TLS можно использовать совершенно обычным образом.

GCC / G ++

Ключевое слово __thread используется как префикс объявления, но реализуется особым образом:

    int variable_globale  ;
    __thread int variable_TLS = 1 ;

Однако переменная TLS должна обязательно инициализироваться константой, известной во время компиляции (случай приведенного выше примера).

Не разрешается объявлять переменную TLS без инициализации или инициализации параметром и / или вызовом функции.

C ++ 11

Начиная со стандарта C ++ 11, язык предоставляет класс хранения thread_local .

Как и в реализациях, специфичных для компилятора, ключевое слово используется в качестве префикса объявления:

    int variable_global ;
    thread_local int variable_TLS ;

Языки

Delphi и Free Pascal

Ключевое слово ThreadVar используется вместо традиционного Var для объявления переменной TLS .

    Var
        variable_globale : Integer ;
    ThreadVar
        variable_TLS : Integer ;

Затем переменную TLS можно использовать совершенно обычным образом.

Ява

В Java переменные TLS реализованы через класс ThreadLocal (en) . Объект ThreadLocalподдерживает отдельный экземпляр переменной для каждого потока, вызывающего методы доступа объекта ( getи set).

В приведенном ниже примере показано, как создать целочисленную переменную TLS  :

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

Переменная используется через методы доступа. Например, приращение:

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

D

В D (версия 2) все статические и глобальные переменные по умолчанию являются локальными для потоков и объявлены как «обычные» переменные для других языков. Это явное объявление «совместно используемой» глобальной переменной, которое требует использования определенного ключевого слова __gshared .

    int variable_TLS ;
    __gshared int variable_globale  ;

Затем переменную TLS можно использовать совершенно обычным образом, как и явно объявленную глобальную переменную.

Языки C # и .NET

Мы используем атрибут ThreadStatic (en)  :

    class classe_avec_TLS {
        [ThreadStatic] static int variable_TLS ;
    }

Кроме того, он может динамически выделять переменные TLS через API Thread.GetNamedDataSlot (in) .

Затем переменную TLS можно использовать совершенно обычным образом.

Python

В Python (версия 2.4 или выше) мы используем локальный класс модуля потоковой передачи для определения переменной TLS .

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

Затем переменную TLS можно использовать совершенно обычным образом.

Рубин

В Ruby переменная TLS создается и используется благодаря методам []=/[].

    Thread.current[:index_TLS] = 1

Perl

Поддержка потоков появилась в языке Perl только поздно, после того, как огромное количество исходного кода было введено в сеть комплексных архивов Perl . В результате этого потоки в Perl по умолчанию создают свой собственный TLS для всех переменных, чтобы минимизировать влияние потоков на существующий небезопасный для потоков код . В Perl переменная, совместно используемая между потоками («нормальный» случай в других языках), создается с помощью атрибута:

    use threads;
    use threads::shared;

    my $variable_TLS;
    my $variable_globale  :shared;

Внешние ссылки

  • Обработка ELF для локального хранилища потоков — документ о реализации на C или C ++ (en) .
  • Статья Дуга Доеденса «  Использование локального хранилища потоков для передачи данных, специфичных для потоков  » (en)
  • «  Локальное хранилище потоков  », Лоуренс Кроул (en)
  • Статья  Уолтера Брайта «Не всегда приятно делиться  » ( фр )

Рекомендации

  1. Локальное хранилище потоков — это библиотека MSDN (en)
  2. man-страница PTHREAD_SPECIFIC — это справочные страницы Linux (in)
  • (fr) Эта статья частично или полностью взята из статьи в англоязычной Википедии под названием «  Локальное хранилище потоков  » ( см. список авторов ) .

Локальная память потока


Все потоки процесса совместно используют свое виртуальное адресное пространство. Локальные переменные функций потока
являются уникальными для каждого потока, который запускает функцию. Однако статические и глобальные переменные
совместно используются всеми потоками этого процесса. При помощи
локальной
памяти потока (thread local storage
,
TLS),
Вы можете обеспечивать уникальными данными каждый поток, который может быть допущен процессом к использованию глобального
индекса. Используя
TLS,
один поток назначает индекс, который может быть использован другим потоком, чтобы получить уникальные данные, связанные с
этим индексом.


Константа TLS_MINIMUM_AVAILABLE
определяет минимальное число индексов локальной памяти потока (
TLS),
доступных в каждом процессе. Этот минимум гарантируется тем, что для всех системам их будет, по меньшей мере, 64. Ограничения для
систем следующие:



Система


Лимит


Windows 2000 и позже


1088 индексов на процесс


Windows 98/Me


80 индексов на процесс

Windows 95

Windows NT 4.0 и ранее


64 индексов на процесс


Когда потоки создаются, система выделяет
массив значений типа
LPVOID
для локальной памяти потока (
TLS),
которые инициализируются значениями ПУСТО (NULL). Раньше индекса, который может быть использован, должен быть назначен один из
потоков. Каждый поток сохраняет свои данные по индексу в массиве
слотов
TLS
(TLS slot).
Если данные, связанные с индексом соответствуют значению типа
LPVOID,
Вы можете сохранять данные непосредственно в слоте
TLS.
Однако если Вы используете большое количество индексов таким образом, лучше выделить отдельную память, объединяющую
данные и минимизировать число слотов
TLS
в использовании.


Нижеследующая диаграмма иллюстрирует, как работает локальная память потока (TLS)
.

Процесс имеет два потока, Поток 1 и Поток 2. Назначается два индекса для использования
с локальной памятью потока (TLS),
gdwTlsIndex1
и
gdwTlsIndex2.
Каждый поток выделяет два блока памяти (один для каждого индекса) в которых сохраняет данные и сохраняет указатели на эти блоки
памяти в соответствующих слотах
TLS.
Чтобы получить доступ к данным, связанным с индексом, поток извлекает указатель на блок памяти из слота
TLS
и сохраняет его в локальной переменной lpvData.


Идеально использовать локальную память потока (TLS)
в динамически подключаемой библиотеке (DLL).
Чтобы реализовать локальную память потока (
TLS)
в DLL, используйте нижеследующие шаги:


  1. Объявите, что глобальная переменная
    содержит индекс
    TLS.
    Например:

    static DWORD gdwTlsIndex;



  2. Используйте функцию TlsAlloc

    в ходе инициализации, чтобы назначить индекс локальной памяти потока (
    TLS).
    Например, включите следующий вызов функции

    DllMain
    во время DLL_PROCESS_ATTACH:

    gdwTlsIndex = TlsAlloc();


  3. Для каждого потока используется индекс локальной памяти потока (TLS),
    который выделяет память для данных, а затем используется функция
    TlsSetValue,
    чтобы сохранить адрес блока памяти в слоте
    TLS,
    связанном с индексом. Например, включите нижеследующий код в вашу функцию
    DllMain
    во время
    DLL_THREAD_ATTACH:

    LPVOID lpvBuffer;
    lpvBuffer = (LPVOID) LocalAlloc(LPTR, 256);
    TlsSetValue(gdwTlsIndex, lpvBuffer);


  4. Когда функция требует доступа к данным, связанным с индексом TLS,
    задайте индекс при вызове функции
    TlsGetValue.
    Это извлечет содержание слота
    TLS
    для вызывающего потока, который в данном случае является указателем на блок памяти для данных. Например, включите
    нижеследующий код в любую из функций в вашу DLL:


    LPVOID lpvData;
    lpvData = TlsGetValue(gdwTlsIndex);


  5. Когда каждому потоку больше не нужно использовать индекс TLS,
    он должен освободить память, указатель на которую сохраняется в слоте
    TLS.
    Когда все потоки закончили использовать индексы
    TLS,
    используйте функцию
    TlsFree,
    чтобы освободить индексы. Например, используйте нижеследующий код в вашей
    DllMain
    во время
    DLL_THREAD_DETACH:




lpvBuffer = TlsGetValue(gdwTlsIndex);
LocalFree((HLOCAL) lpvBuffer);


и нижеследующий код во время DLL_PROCESS_DETACH:



TlsFree(gdwTlsIndex);



Пример, иллюстрирующий использование локальной памяти потока, см.
в статьях
Использование
локальной памяти потока
и

Использование локальной памяти потока в динамически подключаемых библиотеках.


When developing multi-threaded applications using low-level languages such as C, the concept of thread local storage comes up occasionally.  Thread local storage allows global variables to have a unique instance per thread.  Since it only affects global variables, its usefulness is limited but there are some problems that this feature is particularly suited to solve.  One example is keeping track of the locking depth of a mutex.  In some applications, particularly those using callback functions on a user API, there is a possibility that a thread may attempt to lock the same mutex more than once.  This is undesirable behavior because it will lead to deadlock.  One way to avoid this is to count the number of times a thread has tried to lock a mutex, and only do the lock if that number is zero.  Such a counter must have a unique value for each thread.

There are a few ways to declare a global variable with thread local storage in C.  If the compiler supports C11, then thread local storage is standard through <threads.h>, and variables can be declared as ‘thread_local’, as in the following example:

C11

#include <threads.h>

thread_local int foo = 0;

If C11 support is not available, there are some compiler-specific keywords that might be.  The GNU C compiler is commonly used on Linux systems and many versions support the ‘__thread’ keyword to declare thread local variables:

GNU C

On Windows, the Visual C++ compiler supports thread local storage using the following declaration:

Visual C++

__declspec(thread) int foo = 0;

If none of the above methods are available, thread local storage is also supported by the widely used pthread library.  This method is a little more involved than direct compiler support.  The following example shows thread local storage using the pthread library:

pthread

#include <pthread.h>

pthread_key_t global_key = 0;

/* Must be called only once before any threads use global_key */

void global_init() {

    pthread_key_create(&global_key, NULL);

}

/* Called by multiple threads, each has its own unique ptr value */

void thread_function() {

    void *ptr = pthread_getspecific(global_key);

    /* Do some processing */

    pthread_setspecific(global_key, ptr);

}

Понравилась статья? Поделить с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
  • Как создать виртуальный dvd диск в windows 10
  • Windows server 2019 uefi или legacy
  • Не открываются параметры дисплея windows 10
  • Sound blaster sb1095 драйвера windows 10
  • Обои windows 8 beta