Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Локальное хранилище потока (TLS) — это механизм, с помощью которого каждый поток в указанном многопоточном процессе может выделять расположения для хранения данных определенного потока. Динамически привязанные (время выполнения) данные, относящиеся к потоку, поддерживаются через API TLS (TlsAlloc). Win32 и компилятор Microsoft C++ теперь поддерживают статически привязанные (время загрузки) данные для каждого потока в дополнение к существующей реализации API.
Реализация компилятора для TLS
C++11.thread_local Описатель класса хранилища — это рекомендуемый способ указать локальное хранилище потока для объектов и членов класса. Дополнительные сведения см. в разделе "Классы хранилища" (C++).
MSVC также предоставляет атрибут, поток, определенный корпорацией Майкрософт, как модификатор расширенного класса хранилища. Используйте ключевое __declspec слово для объявления переменной thread . В следующем примере кода показано, как объявлять целочисленную локальную переменную потока и инициализировать её некоторым значением:
__declspec( thread ) int tls_i = 1;
Правила и ограничения
При объявлении статистически связываемых локальных объектов и переменных потока необходимо соблюдать следующие рекомендации. Эти рекомендации применяются как к потоку, так и к thread_local:
Атрибут
threadможно применять только к объявлениям и определениям классов и данных. Его нельзя использовать для объявлений или определений функций. Например, следующий код вызовет ошибку компиляции:__declspec( thread )void func(); // This will generate an error.threadМодификатор можно указать только для элементов данных сstaticэкстентом. Это включает глобальные объекты данных (как и ), локальные статические объекты, такstaticиexternстатические элементы данных классов C++. Автоматические объекты данных не могут быть объявлены атрибутомthread. Следующий код вызывает ошибки компилятора: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; }Объявления и определение локального объекта потока должны указывать
threadатрибут. Например, следующий код вызывает ошибку:#define Thread __declspec( thread ) extern int tls_i; // This will generate an error, since the int __declspec( thread )tls_i; // declaration and definition differ.Атрибут
threadнельзя использовать в качестве модификатора типа. Например, следующий код вызовет ошибку компиляции:char __declspec( thread ) *ch; // ErrorТак как объявление объектов C++, использующих
threadатрибут, разрешено, следующие два примера семантически эквивалентны:__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.Адрес локального объекта потока не считается константой, и любое выражение, связанное с таким адресом, не считается константным выражением. В стандартном C эффект заключается в запрете использования адреса локальной переменной потока в качестве инициализатора для объекта или указателя. Например, компилятор C отмечает следующий код как ошибочный:
__declspec( thread ) int tls_i; int *p = &tls_i; //This will generate an error in C.Это ограничение не применяется в C++. Так как C++ допускает динамическую инициализацию всех объектов, можно инициализировать объект с помощью выражения, которое использует адрес локальной переменной потока. Это делается так же, как создание локальных объектов потока. Например, код, показанный ранее, не создает ошибку при компиляции в виде исходного файла C++. Адрес локальной переменной потока действителен, только если поток, в котором был взят адрес, по-прежнему существует.
Стандарт C позволяет инициализации объекта или переменной с выражением, которое включает ссылку на себя, но только для объектов нестатической степени. Хотя C++ обычно допускает такую динамическую инициализацию объектов с выражением, которое включает ссылку на себя, такой тип инициализации не допускается с локальными объектами потока. Например:
__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++sizeofВыражение, включающее инициализированный объект, не представляет ссылку на себя и включается как в C, так и в C++.C++ не разрешает такую динамическую инициализацию данных потока из-за возможных будущих улучшений локального хранилища потока.
В операционных системах Windows до Windows Vista
__declspec( thread )есть некоторые ограничения. Если библиотека DLL объявляет любые данные или объект как__declspec( thread ), это может привести к сбою защиты при динамической загрузке. После загрузки библиотеки DLL с помощью LoadLibrary происходит сбой системы, когда код ссылается на__declspec( thread )данные. Поскольку пространство глобальных переменных для потока выделяется во время выполнения, размер данного пространства основан на расчете требований приложению, а также требований всех библиотек DLL, которые привязываются статически. При использованииLoadLibraryвы не можете расширить это пространство, чтобы разрешить локальные переменные потока, объявленные с__declspec( thread )помощью . Используйте API TLS, такие как TlsAlloc, в библиотеке DLL, чтобы выделить TLS, если библиотека DLL может быть загружена.LoadLibrary
См. также
Реализация многопоточности на языке C с помощью функций Win32