Локальное хранилище потока: статические поля потока и области данныхThread Local Storage: Thread-Relative Static Fields and Data Slots

Вы можете использовать управляемое локальное по отношению к потоку хранилище (TLS) для хранения данных, которые являются уникальными для потока и домена приложения.You can use managed thread local storage (TLS) to store data that's unique to a thread and application domain. Платформа .NET предоставляет два способа работы с TLS: статические поля потоков и ячейки данных..NET provides two ways to use managed TLS: thread-relative static fields and data slots.

  • Статические поля потоков (поля потоков Shared в Visual Basic) можно применять, если вы можете точно прогнозировать потребности во время компиляции.Use thread-relative static fields (thread-relative Shared fields in Visual Basic) if you can anticipate your exact needs at compile time. Статические поля потоков обеспечивают более высокую производительность.Thread-relative static fields provide the best performance. Они также позволяют выполнять проверки типов во время компиляции.They also give you the benefits of compile-time type checking.

  • Если фактические требования могут определяться только во время выполнения, используйте области данных.Use data slots when your actual requirements might be discovered only at run time. Области данных работают медленнее и менее удобны в использовании, чем статические поля потоков. Данные в них хранятся в качестве типа Object, поэтому перед использованием необходимо привести их к правильному типу.Data slots are slower and more awkward to use than thread-relative static fields, and data is stored as type Object, so you must cast it to the correct type before you use it.

В неуправляемом коде C++ используются TlsAlloc для динамического выделения областей данных и __declspec(thread) для объявления переменных, которые нужно выделять в хранилище потока.In unmanaged C++, you use TlsAlloc to allocate slots dynamically and __declspec(thread) to declare that a variable should be allocated in thread-relative storage. Статические поля потоков и области данных реализуют такое же поведение для управляемого кода.Thread-relative static fields and data slots provide the managed version of this behavior.

Вы можете использовать класс System.Threading.ThreadLocal<T> для создания локальных по отношению к потоку объектов с отложенной инициализацией (при первом использовании объекта).You can use the System.Threading.ThreadLocal<T> class to create thread-local objects that are initialized lazily when the object is first consumed. Дополнительные сведения см. в статье Отложенная инициализация.For more information, see Lazy Initialization.

Уникальность данных в управляемой локальной памяти потокаUniqueness of Data in Managed TLS

Независимо от того, что вы используете — статические поля потоков или области данных — данные в управляемой локальной памяти потока являются уникальными для определенной комбинации потока и домена приложения.Whether you use thread-relative static fields or data slots, data in managed TLS is unique to the combination of thread and application domain.

  • Любой поток в домене приложения не может изменять данные другого потока, даже если оба потока используют одинаковые поля или области памяти.Within an application domain, one thread cannot modify data from another thread, even when both threads use the same field or slot.

  • Если поток обращается к одному полю или области через разные домены приложений, в каждом домене приложения для него хранится отдельное значение.When a thread accesses the same field or slot from multiple application domains, a separate value is maintained in each application domain.

Таким образом, если поток устанавливает значение для статического поля потока, затем переходит в другой домен приложения и извлекает значение этого поля, он получит во втором домене приложения другое значение, отличное от значения в первом домене приложения.For example, if a thread sets the value of a thread-relative static field, enters another application domain, and then retrieves the value of the field, the value retrieved in the second application domain differs from the value in the first application domain. Сохранение нового значения для поля во втором домене приложения никак не влияет на значение этого поля в первом домене приложения.Setting a new value for the field in the second application domain does not affect the field's value in the first application domain.

Аналогичным образом, если поток получает одинаковую именованную область данных в двух разных доменах приложений, данные в первом домене не будут зависеть от данных во втором домене приложения.Similarly, when a thread gets the same named data slot in two different application domains, the data in the first application domain remains independent of the data in the second application domain.

Статические поля потоковThread-Relative Static Fields

Если вы твердо уверены, что некоторые данные всегда уникальны для потока и домена приложения, примените для статического поля атрибут ThreadStaticAttribute.If you know that a piece of data is always unique to a thread and application-domain combination, apply the ThreadStaticAttribute attribute to the static field. Используйте это поле так же, как любое обычное статическое поле.Use the field as you would use any other static field. Данные в этом поле всегда будут уникальными для каждого потока, который его использует.The data in the field is unique to each thread that uses it.

Статические поля потоков обеспечивают более высокую производительность, чем области данных, и позволяют выполнять проверку типов во время компиляции.Thread-relative static fields provide better performance than data slots and have the benefit of compile-time type checking.

Имейте в виду, что любой код конструктора класса будет выполняться в первом потоке в первом контексте, где происходит обращение к полю.Be aware that any class constructor code will run on the first thread in the first context that accesses the field. Во всех других потоках и (или) контекстах в том же домене приложения эти поля получают значения null (Nothing в Visual Basic), а если они являются ссылочными типами, — значения по умолчанию для соответствующих типов.In all other threads or contexts in the same application domain, the fields will be initialized to null (Nothing in Visual Basic) if they are reference types, or to their default values if they are value types. Таким образом, вы не можете инициализировать статические поля потоков через конструктор класса.Therefore, you should not rely on class constructors to initialize thread-relative static fields. Старайтесь не применять инициализацию для статических полей потоков, и всегда предполагайте, что они имеют значение null (Nothing) или значение по умолчанию для типа.Instead, avoid initializing thread-relative static fields and assume that they are initialized to null (Nothing) or to their default values.

Области данныхData Slots

.NET предоставляет динамически выделяемые ячейки данных, которые являются уникальными для каждой комбинации потока и домена приложения..NET provides dynamic data slots that are unique to a combination of thread and application domain. Есть два типа областей данных: именованные и безымянные.There are two types of data slots: named slots and unnamed slots. Оба типа реализуются с помощью структуры LocalDataStoreSlot.Both are implemented by using the LocalDataStoreSlot structure.

Как для именованных, так и для неименованных областей данных можно применять методы Thread.SetData и Thread.GetData для сохранения и получения данных.For both named and unnamed slots, use the Thread.SetData and Thread.GetData methods to set and retrieve the information in the slot. Это статические методы, которые всегда работают с данными того потока, который их выполняет.These are static methods that always act on the data for the thread that is currently executing them.

Именованные области особенно удобны, так как позволяют в любой момент получить нужную область, передав ее имя в метод GetNamedDataSlot, вместо того чтобы хранить ссылку на безымянную область.Named slots can be convenient, because you can retrieve the slot when you need it by passing its name to the GetNamedDataSlot method, instead of maintaining a reference to an unnamed slot. Но если другой компонент использует то же имя в своем хранилище потока, при выполнении в одном потоке кода из обоих этих компонентов они могут повредить данные друг друга.However, if another component uses the same name for its thread-relative storage and a thread executes code from both your component and the other component, the two components might corrupt each other's data. (Здесь предполагается, что оба компонента работают в одном домене приложения и не рассчитаны на совместное использование данных.)(This scenario assumes that both components are running in the same application domain, and that they are not designed to share the same data.)

См. также разделSee also