上面这段代码的步骤很清楚 。
- 创建 ThreadLocalModule
- 初始化 MethodTable 类型的字段 pMT
结合刚才汇编中的 mov edx,4 以及源码发现是取 IL 元数据中的 Program,参考代码及截图如下:
FORCEINLINE MethodTable * GetMethodTableFromClassDomainID(DWORD dwClassDomainID){DWORD rid = (DWORD)(dwClassDomainID) + 1;TypeHandle th = GetDomainFile()->GetModule()->LookupTypeDef(TokenFromRid(rid, mdtTypeDef));MethodTable * pMT = th.AsMethodTable();return pMT;}
文章插图
图片
也可以用 windbg 在 JIT_GetNonGCThreadStaticBase_Helper 方法的 return 处下一个断点,参考如下:
0:008> r ecxecx=0564ef280:008> !dumpmt 0564ef28EEClass:056d14d0Module:0564db08Name:ConsoleApp7.ProgrammdToken:02000005File:D:codeMyApplicationConsoleApp7binx86Debug.NET6.0ConsoleApp7.dllAssemblyLoadContext: Default ALC - The managed instance of this context doesn't exist yet.BaseSize:0xcComponentSize:0x0DynamicStatics:falseContainsPointers:falseSlots in VTable:8Number of IFaces in IFaceMap: 0
到这里就真相大白了,thread1 在执行时,用 CheckRunClassInitThrowing 方法发现 Program 没有被静态构造过 , 所以就执行了,即 num=10 ,当 thread2 执行时,发现已经被构造过了,所以就不再执行静态构造函数,所以就成了默认值 num=0 。3. 如何复验你的结论刚才我说 thread1 做了一个是否执行静态构造的判断 , 其实这里我可以做个手脚,在 Main 之前先把 Program 静态函数给执行掉,按理说 thread1 和 thread2 此时都会是默认值 num=0 , 对不对,哈哈,试一试呗,简化代码如下:
internal class Program{[ThreadStatic]public static int num = 10;/// <summary>/// 先于 main 执行/// </summary>static Program(){}static void Main(string[] args){Test();Console.ReadLine();}}
文章插图
图片
哈哈 , 此时都是 0 了,也就再次验证了我的结论 。
三:总结在 C# 开发中经常会有一些疑惑,如果不了解汇编 , C++ ,相信你会陷入到很多的魔法使用中而苦于不能独自解惑的遗憾 。
【C# 线程本地存储为什么线程间值不一样】
推荐阅读
- 《外来媳妇本地郎》卢秋萍,戏里是妙婵妈妈,戏外女儿身份不简单
- 外来媳妇本地郎再也见不到的美女,“处长夫人”刘亚菲已回归家庭
- 本地连接受限制或无连接解决方法
- 微信iOS版大更新,存储空间瘦身
- 外地银行卡丢了可以在本地补办吗 外地银行卡丢了可以在本地补办吗农业银行
- 手机存储的奥秘:深入解析闪存技术的工作原理
- Spring Boot虚拟线程的性能还不如Webflux?
- 苹果手机该咋滴才可以下抖音,苹果手机本地视频怎样上传抖音
- 深入理解与应用多线程技术
- 在 Rust 编程中使用多线程