zoukankan      html  css  js  c++  java
  • 多线程中Local Store Slot(本地存储槽)[转]

    1. 使用ThreadStatic特性

    ThreadStatic特性是最简单的TLS使用,且只支持静态字段,只需要在字段上标记这个特性就可以了:

    1. [ThreadStatic]  
    2. static string str = "hehe";  
    3. static void Main()  
    4. {  
    5. //另一个线程只会修改自己TLS中的str变量
    6.     Thread th = new Thread(() => { str = "Mgen"; Display(); });  
    7.     th.Start();  
    8.     th.Join();  
    9.     Display();  
    10. }  
    11. static void Display()  
    12. {  
    13.     Console.WriteLine("{0} {1}", Thread.CurrentThread.ManagedThreadId, str);  

    运行结果:

    1 hehe
    3 Mgen

    可以看到,str静态字段在两个线程中都是独立存储的,互相不会被修改。

    2. 使用命名的LocalDataStoreSlot类型

    显然ThreadStatic特性只支持静态字段太受限制了。.NET线程类型中的LocalDataStoreSlot提供更好的TLS支持。我们先来看看命名的LocalDataStoreSlot类型,可以通过Thread.AllocateNamedDataSlot来分配一个命名的空间,通过Thread.FreeNamedDataSlot来销毁一个命名的空间。空间数据的获取和设置则通过Thread类型的GetData方法和SetData方法。

    1. static void Main()  
    2. {  
    3. //创建Slot
    4.     LocalDataStoreSlot slot = Thread.AllocateNamedDataSlot("slot");  
    5. //设置TLS中的值
    6.     Thread.SetData(slot, "hehe");  
    7. //修改TLS的线程
    8.     Thread th = new Thread(() =>  
    9.         {  
    10.             Thread.SetData(slot, "Mgen");  
    11.             Display();  
    12.         });  
    13.     th.Start();  
    14.     th.Join();  
    15.     Display();  
    16. //清除Slot
    17.     Thread.FreeNamedDataSlot("slot");  
    18. }  
    19. //显示TLS中Slot值
    20. static void Display()  
    21. {  
    22.     LocalDataStoreSlot dataslot = Thread.GetNamedDataSlot("slot");  
    23.     Console.WriteLine("{0} {1}", Thread.CurrentThread.ManagedThreadId, Thread.GetData(dataslot));  

    输出:

    3 Mgen
    1 hehe

    3. 使用未命名的LocalDataStoreSlot类型

    线程同样支持未命名的LocalDataStoreSlot,未命名的LocalDataStoreSlot不需要手动清除,分配则需要Thread.AllocateDataSlot方法。注意由于未命名的LocalDataStoreSlot没有名称,因此无法使用Thread.GetNamedDataSlot方法,只能在多个线程中引用同一个LocalDataStoreSlot才可以对TLS空间进行操作,将上面的命名的LocalDataStoreSlot代码改成未命名的LocalDataStoreSlot执行:

    1. //静态LocalDataStoreSlot变量
    2. static LocalDataStoreSlot slot;  
    3. static void Main()  
    4. {  
    5. //创建Slot
    6.     slot = Thread.AllocateDataSlot();  
    7. //设置TLS中的值
    8.     Thread.SetData(slot, "hehe");  
    9. //修改TLS的线程
    10.     Thread th = new Thread(() =>  
    11.         {  
    12.             Thread.SetData(slot, "Mgen");  
    13.             Display();  
    14.         });  
    15.     th.Start();  
    16.     th.Join();  
    17.     Display();  
    18. }  
    19. //显示TLS中Slot值
    20. static void Display()  
    21. {  
    22.     Console.WriteLine("{0} {1}", Thread.CurrentThread.ManagedThreadId, Thread.GetData(slot));  
    23. }  

    4. 使用.NET 4.0的ThreadLocal<T>类型

    .NET 4.0在线程方面加入了很多东西,其中就包括ThreadLocal<T>类型,他的出现更大的简化了TLS的操作。ThreadLocal<T>类型和Lazy<T>惊人相似,构造函数参数是Func<T>用来创建对象(当然也可以理解成对象的默认值),然后用Value属性来得到或者设置这个对象。ThreadLocal的操作或多或少有点像上面的未命名的LocalDataStoreSlot,但ThreadLocal感觉更简洁更好理解。

    1. static ThreadLocal<string> local;  
    2. static void Main()  
    3. {  
    4. //创建ThreadLocal并提供默认值
    5.     local = new ThreadLocal<string>(() => "hehe");  
    6. //修改TLS的线程
    7.     Thread th = new Thread(() =>  
    8.         {  
    9.             local.Value = "Mgen";  
    10.             Display();  
    11.         });  
    12.     th.Start();  
    13.     th.Join();  
    14.     Display();  
    15. }  
    16. //显示TLS中数据值
    17. static void Display()  
    18. {  
    19.     Console.WriteLine("{0} {1}", Thread.CurrentThread.ManagedThreadId, local.Value);  

    输出:

    3 Mgen

    1 hehe 

    5. 强调一下不同方法和TLS的默认值
    上面代码都是一个一个线程设置值,另一个线程直接修改值然后输出,不会觉察到TLS中默认值的状况,下面专门强调一下不同方法的默认值状况。ThreadStatic不提供默认值:

    1. [ThreadStatic]  
    2. static int i = 123;  
    3. static void Main()  
    4. {  
    5. //输出本地线程TLS数据值
    6.     Console.WriteLine(i);  
    7. //输出另一个线程TLS数据值
    8.     ThreadPool.QueueUserWorkItem(_ => Console.WriteLine(i));  
    9. //控制台等待线程结束
    10.     Console.ReadKey();  

    输出:
    123

    0

    显然本地线程TLS数据时123,而静态变量的默认值不会在另一个线程中初始化的。

    LocalDataStoreSlot很容易可以看出来,不可能有默认值,因为初始化只能构造一个空间,而不能赋予它值,Thread.SetData显然只会在TLS中设置数据,还是用代码演示一下:

    1. static LocalDataStoreSlot slot = Thread.AllocateDataSlot();  
    2. static void Main()  
    3. {  
    4.     Thread.SetData(slot, 123);  
    5. //输出本地线程TLS数据值
    6.     Console.WriteLine(Thread.GetData(slot));  
    7. //输出另一个线程TLS数据值
    8.     ThreadPool.QueueUserWorkItem(_ => Console.WriteLine(Thread.GetData(slot) == null));  
    9. //控制台等待线程结束
    10.     Console.ReadKey();  

    输出:
    123
    True
    第二行是True,那么另一个线程中的数据是null。

    最后重点:.NET 4.0后的ThreadLocal会提供默认值的,还记得我上面说的那句话“ThreadLocal的操作或多或少有点像上面的未命名的LocalDataStoreSlot”?有人可能会问那为什么要创造出ThreadLocal?还有一个很大的区别ThreadLocal可以提供TLS中数据的默认值。(另外还有ThreadLocal是泛型类,而LocalDataStoreSlot不是)。

    1. static ThreadLocal<int> local = new ThreadLocal<int>(() => 123);  
    2. static void Main()  
    3. {  
    4. //输出本地线程TLS数据值
    5.     Console.WriteLine(local.Value);  
    6. //输出另一个线程TLS数据值
    7.     ThreadPool.QueueUserWorkItem(_ => Console.WriteLine(local.Value));  
    8. //控制台等待线程结束
    9.     Console.ReadKey();  

    输出:
    123
    123

    这篇文章也可以参考

    http://www.cnblogs.com/lulu/archive/2012/03/17/2403872.html

  • 相关阅读:
    UML中的构件图
    Extjs4 中的gird
    【转载】C#实现线程安全的网络流
    [转载]组播
    【转载】wcf综合运用之:大文件异步断点续传
    【转载】WCF热门问题编程示例(4):WCF客户端如何异步调用WCF服务?
    【转载】特殊用途的IP地址介绍
    [转载]C# HashTable
    c宏定义实战
    c异或加密与解密
  • 原文地址:https://www.cnblogs.com/chenqingwei/p/5003688.html
Copyright © 2011-2022 走看看