ThreadStatic 属性如何工作?
[ThreadStatic]
属性如何工作?我假设编译器会发出一些 IL 来填充/检索 TLS 中的值,但查看反汇编结果似乎并没有在该级别执行此操作。
作为后续,如果将其放在非静态成员上会发生什么?我们有一个开发人员犯了这个错误,而编译器甚至没有提供警告。
更新
这里回答了第二个问题:ThreadStatic Modified with Static C#
How does [ThreadStatic]
attribute work? I assumed that the compiler would emit some IL to stuff/retrieve the value in the TLS, but looking at a disassembly it doesn't seem to do it at that level.
As a follow up, what happens if you put it on a non-static member? We had a developer make that mistake and the compiler doesn't even proffer up a warning.
Update
Second question answered here: ThreadStatic Modified with Static C#
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您可以认为标有 ThreadStatic 的字段附加到线程及其生命周期与线程的生命周期相当。
因此,在伪代码中,
ThreadStatic
(从语义上来说)类似于将键值附加到线程:但语法更简单一些:
我相信它被忽略了:
此外值得一提的是,与普通静态字段相比,ThreadStatic 不需要任何同步机制(因为状态不共享)。
You can think that the field marked with ThreadStatic is attached to a thread and its lifetime is comparable to the lifetime of a thread.
So in pseudocode
ThreadStatic
is similar (by semantics) to having a key-value attached to a thread:but the syntax is just a bit easier:
I believe it is ignored:
Additionally it is worth mentioning that
ThreadStatic
does not require any synchronisation mechanism as compared to normal static fields (because the state is not shared).在 .NET jit 编译器中,线程静态的实现语义低于 IL 级别。发出 IL 的编译器(例如 VB.NET 和 C#)不需要了解有关 Win32 TLS 的任何信息,即可发出可以读取和写入具有 ThreadStatic 属性的变量的 IL 代码。就 C# 所知,该变量没有什么特别之处 - 它只是一个读取和写入内容的位置。它具有属性这一事实对于 C# 来说并不重要。 C# 只需要知道为该符号名称发出 IL 读或写指令。
“繁重的工作”是由核心 CLR 完成的,它负责使 IL 在特定的硬件架构上工作。
这也可以解释为什么将属性放在不适当的(非静态)符号上不会得到编译器的反应。编译器不知道该属性需要什么特殊语义。不过,像 FX/Cop 这样的代码分析工具应该了解这一点。
另一种看待方式:CIL 定义了一组存储范围:静态(全局)存储、成员存储和堆栈存储。 TLS 不在该列表中,很可能是因为 TLS 不需要在该列表中。如果当符号标记有 TLS 属性时,IL 读写指令足以访问 TLS,那么为什么 IL 应对 TLS 有任何特殊的表示或处理呢?不需要。
The implementation semantics of thread static are below the IL level, in the .NET jit compiler. Compilers that emit to IL like VB.NET and C# don't need to know anything about Win32 TLS in order to emit IL code that can read and write a variable that has the ThreadStatic attribute. There's nothing special about the variable as far as C# knows - it's just a location to read and write stuff. The fact that it has an attribute on it is of no consequence to C#. C# only needs to know to emit IL read or write instructions for that symbol name.
The 'heavy lifting' is done by the core CLR that is responsible for making the IL work on a particular hardware architecture.
That would also explain why putting the attribute on an inappropriate (non-static) symbol doesn't get a reaction from the compiler. The compiler doesn't know what special semantics the attribute requires. Code analysis tools like FX/Cop, though, should know about it.
Another way to look at it: CIL defines a set of storage scopes: static (global) storage, member storage, and stack storage. TLS isn't on that list, very likely because TLS doesn't need to be on that list. If IL read and write instructions are sufficient to access TLS when the symbol is tagged with a TLS attribute, why should IL have any special representation or treatment for TLS? It's not needed.
[ThreadStatic] 在每个线程中创建同一变量的隔离版本。
例子:
The [ThreadStatic] creates isolated versions of the same variable in each thread.
Example:
标记为[ThreadStatic]的字段是在线程本地存储上创建的,因此每个线程都有自己的字段副本,即字段的范围是线程本地的。
TLS 字段是通过 gs/fs 段寄存器访问的。操作系统内核使用这些段来访问线程特定的内存。.net 编译器不会发出任何 IL 来填充/检索 TLS 中的值。它是由操作系统内核完成的。
The field marked with
[ThreadStatic]
are created on Thread Local Storage so every thread has it own copy of the field i.e the scope of the fields are local to the thread.TLS fields are access through gs/fs segments registers.These segments are used by the OS kernels to access thread-specific memory.The .net compiler do not emit any IL to stuff/retrieve the value in the TLS. It is done by the OS kernel.
用 ThreadStaticAttribute 标记的静态字段不在线程之间共享。每个执行线程都有一个单独的字段实例,并独立设置和获取该字段的值。如果在不同的线程上访问该字段,它将包含不同的值。
A static field marked with
ThreadStaticAttribute
is not shared between threads. Each executing thread has a separate instance of the field, and independently sets and gets values for that field. If the field is accessed on a different thread, it will contain a different value.