如果你正在寻找一些关于线程本地存储的内容,你可能会对performance comparison between Thread.SetData and [ThreadStatic].感兴趣。
ThreadStatic 超级酷,如果你有一个静态变量,你可以通过在属性上面设置它来使这个属性对“每个线程”是静态的。这是一个简单的绕过使用静态变量时的线程安全性问题的方法- 由于它们是一个线程一个的,当你更新它们时你不必使用锁。
[ThreadStatic] private static string Foo;
现在可以绊倒你的就是初始化了。
[ThreadStatic] private static string Foo = "the foo string";
TreadStatic 在静态构造函数中初始化 - 它只执行一次。所以只有当静态构造函数执行时,第一个执行的线程才会被赋值"the foo string".当顺序访问所有的线程时,Foo 仍然是未初始化的空值。
最好的绕过这个问题的方法是使用一个属性来访问Foo属性。
[ThreadStatic] private static string _foo; public static string Foo { get { if (_foo == null) { _foo = "the foo string"; } return _foo; } }
如果你有一些可以合理地设置为空值的属性,你可以总是使用一个静态线程布尔属性"_fooInitialized".
[ThreadStatic] private static string _foo; [ThreadStatic] private static bool _fooInitialized; public static string Foo { get { if (!_fooInitialized) { _fooInitialized = true; _foo = "the foo string"; } return _foo; } }
而且如果你有很多布尔型变量,你可能想要节省空间;无论你是否相信一个布尔型变量占据珍贵的比特(可以通过打印出Marshal.SizeOf(typeof(bool))来获取额外的证据)。
你可以把它们合并成一个比特变量来节省空间。
[ThreadStatic] private static string _foo; [ThreadStatic] private static string _goo; [ThreadStatic] private static BitVector32 _state = new BitVector32(); private const int stateFooInitialized = 0x0001; private const int stateGooInitialized = 0x0002; // ... 0x0004, 0x0008 ... public static string Foo { get { if (!_state[stateFooInitialized]) { _state[stateFooInitialized] = true; _foo = "the foo string"; } return _foo; } } public static string Goo { get { if (!_state[stateGooInitialized]) { _state[stateGooInitialized] = true; _goo = "the goo string"; } return _goo; } }