来自 电脑系统 2019-11-28 05:52 的文章
当前位置: 金沙澳门官网网址 > 电脑系统 > 正文

线程安全类型,NET并行计算和并发4

金沙澳门官网网址 1金沙澳门官网网址 2

Thread Local Storage: Thread-Relative Static Fields and Data Slots



小说摘自msdn library官方文书档案

能够采取托管线程本地存储区 (TLS) 存款和储蓄某一线程和平运动用程序域所独有的数码。 .NET Framework 提供了三种接纳托管 TLS 的方法:线程相关的静态字段和数据槽。

  • 设若你能够在编写翻译时预料到您的适当要求,请使用线程相关的静态字段(在 Visual Basic 中为线程相关的 Shared 字段卡塔尔国。 线程相关的静态字段可提供最好质量。 它们还装有编写翻译时类型检查的亮点。

  • 意气风发经一定要在运维时发掘你的其实须要,请使用数据槽。 数据槽比线程相关的静态字段慢一些且更为困难使用,况且数据存款和储蓄为 Object.aspx) 类型,由此必需将其挟持调换为科学的品类本领选择。

在非托管 C++ 中,可以应用 TlsAlloc 来动态分配槽,使用 __declspec(thread) 来证明变量应在线程相关的存款和储蓄区中开展分红。 线程相关的静态字段和数据槽提供了此表现的托管版本。

在 .NET Framework 4中,尚可 System.Threading.ThreadLocal<T>.aspx) 类创制线程当地对象,在首先次选拔该指标时它将惰式初步化。 有关详细音信,请参阅延迟初阶化.aspx)。

托管 TLS 中数量的唯风度翩翩性

 

无论使用线程相关的静态字段依旧使用数据槽,托管 TLS 中的数据都是线程和应用程序域组合所唯有的。

  • 在行使程序域内部,三个线程不可能改改另三个线程中的数据,纵然那三个线程使用同四个字段或槽时也不能够。

  • 当线程从五个利用程序域中做客同三个字段或槽时,会在种种应用程序域中爱惜四个独自的值。

举个例子说,若是某些线程设置线程相关的静态字段的值,接着它步入另二个施用程序域,然后寻找该字段的值,则在首个利用程序域中检索的值将不相同于第二个使用程序域中的值。 在第一个应用程序域中为该字段设置七个新值不会潜移默化率先个使用程序域中该字段的值。

风流罗曼蒂克律,当某些线程获取多少个例外应用程序域中的同一命名数据槽时,第4个应用程序域中的数据将始终与第二个利用程序域中的数据非亲非故。

线程相关的静态字段

 

设若你精通有个别数码连接有些线程和应用程序域组合所唯有的,请向该静态字段应用 ThreadStaticAttribute.aspx) 天性。 与应用其它别的静态字段雷同选拔该字段。 该字段中的数据是每一种使用它的线程所独有的。

线程相关的静态字段的本性优于数据槽,並且有着编写翻译时类型检查的亮点。

请在乎,任何类布局函数代码都将要会见该字段的率先个上下文中的第1个线程上运营。 在同等应用程序域内的具备其余线程或左右文中,假诺字段是援引类型,它们将被开头化为 null金沙澳门官网网址 ,(在 Visual Basic 中为 Nothing卡塔尔;如果字段是值类型,它们将被早先化为它们的暗中同意值。 因而,您不应依赖于类布局函数来开始化线程相关的静态字段。 而应防止初叶化线程相关的静态字段并假定它们开端化为 null (Nothing) 或它们的暗中认可值。

数据槽

 

.NET Framework 提供了线程和接纳程序域组合所只有的动态数据槽。 数据槽包含二种档期的顺序:命名槽和未命名槽。 两个都以经过行使LocalDataStoreSlot.aspx) 布局来兑现的。

  • 若要创造命名数据槽,请使用 Thread.AllocateNamedDataSlot.aspx) 或 Thread.GetNamedDataSlot.aspx) 方法。 若要博取对有个别现成命名槽的援用,请将其名目传递给 GetNamedDataSlot.aspx) 方法。

  • 若要创设未命名数据槽,请使用 Thread.AllocateDataSlot.aspx) 方法。

对于命名槽和未命名槽,请使用 Thread.SetData.aspx) 和 Thread.GetData.aspx) 方法设置和检索槽中的新闻。 这一个都以静态方法,它们平昔效率于当下正值奉行它们的线程的多少。

命名槽只怕很方便,因为你能够在须要它时通过将其名目传递给 GetNamedDataSlot.aspx) 方法来寻觅该槽,并不是保卫安全对未命名槽的引用。 可是,固然另三个零器件使用相近的名目来定名其线程相关的存款和储蓄区,何况有叁个线程同不时候推行来自您的零零器件和该零部件的代码,则那八个零器件大概会破坏相互的数据。(本方案意气风发经那四个零器件在长期以来应用程序域内运转,何况它们并不用于共享相近数量。卡塔 尔(英语:State of Qatar)

10、使用.NET 4.0的ThreadLocal<T>类型
  .NET 4.0在线程方面投入了众多东西,此中就总结ThreadLocal<T>类型,他的产出越来越大的简化了TLS的操作。ThreadLocal<T>类型和Lazy<T>惊人相似,构造函数参数是Func<T>用来成立对象(当然也得以明白成靶子的暗中认可值卡塔尔国,然后用Value属性来获得或然设置那些指标。
  ThreadLocal的操作或多或罕有一点像上面的未命名的LocalDataStoreSlot,但ThreadLocal感觉更轻松越来越好明白。

Module

using System;
using System.Collections.Concurrent;

namespace ConsoleApp1
{
    class Program
    {
        static void Main()
        {
            TestSafeStack();

            // Keep the console window open in debug mode.
            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }

        // Test our implementation of IProducerConsumerCollection(T)
        // Demonstrates:
        //      IPCC(T).TryAdd()
        //      IPCC(T).TryTake()
        //      IPCC(T).CopyTo()
        static void TestSafeStack()
        {
            SafeStack<int> stack = new SafeStack<int>();
            IProducerConsumerCollection<int> ipcc = (IProducerConsumerCollection<int>)stack;

            // Test Push()/TryAdd()
            stack.Push(10); Console.WriteLine("Pushed 10");
            ipcc.TryAdd(20); Console.WriteLine("IPCC.TryAdded 20");
            stack.Push(15); Console.WriteLine("Pushed 15");

            int[] testArray = new int[3];

            // Try CopyTo() within boundaries
            try
            {
                ipcc.CopyTo(testArray, 0);
                Console.WriteLine("CopyTo() within boundaries worked, as expected");
            }
            catch (Exception e)
            {
                Console.WriteLine("CopyTo() within boundaries unexpectedly threw an exception: {0}", e.Message);
            }

            // Try CopyTo() that overflows
            try
            {
                ipcc.CopyTo(testArray, 1);
                Console.WriteLine("CopyTo() with index overflow worked, and it SHOULD NOT HAVE");
            }
            catch (Exception e)
            {
                Console.WriteLine("CopyTo() with index overflow threw an exception, as expected: {0}", e.Message);
            }

            // Test enumeration
            Console.Write("Enumeration (should be three items): ");
            foreach (int item in stack)
                Console.Write("{0} ", item);
            Console.WriteLine("");

            // Test TryPop()
            int popped = 0;
            if (stack.TryPop(out popped))
            {
                Console.WriteLine("Successfully popped {0}", popped);
            }
            else Console.WriteLine("FAILED to pop!!");

            // Test Count
            Console.WriteLine("stack count is {0}, should be 2", stack.Count);

            // Test TryTake()
            if (ipcc.TryTake(out popped))
            {
                Console.WriteLine("Successfully IPCC-TryTaked {0}", popped);
            }
            else Console.WriteLine("FAILED to IPCC.TryTake!!");
        }
    }
}

金沙澳门官网网址 3金沙澳门官网网址 4

金沙澳门官网网址 5金沙澳门官网网址 6

Program

CrawlingTask

Program

Program

Program

using System;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        static ThreadLocal<string> local;

        static void Main(string[] args)
        {
            //创建ThreadLocal并提供默认值
            local = new ThreadLocal<string>(() => "hehe");

            //修改TLS的线程
            Thread th = new Thread(() =>
            {

                local.Value = "Mgen";
                Display();
            });

            th.Start();
            th.Join();
            Display();
        }

        //显示TLS中数据值
        static void Display()
        {
            Console.WriteLine("{0} {1}", Thread.CurrentThread.ManagedThreadId, local.Value);
        }

    }
}
using System;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        //TLS中的str变量
        //可以看到,str静态字段在两个线程中都是独立存储的,互相不会被修改。
        [ThreadStatic]
        static string str = "hehe";

        static void Main(string[] args)
        {
            //另一个线程只会修改自己TLS中的hehe
            Thread th = new Thread(() => { str = "Mgen"; Display(); });
            th.Start();
            th.Join();
            Display();
        }
        static void Display()
        {
            Console.WriteLine("{0} {1}", Thread.CurrentThread.ManagedThreadId, str);
        }

    }
}

Program

Program

金沙澳门官网网址 7金沙澳门官网网址 8

4、ConcurrentDictionary类
  ConcurrentDictionary类写操作比使用锁的经常字典(Dictionary)要慢的多,而读操作则要快些。由此对字典要豁达的线程安全的读操作,ConcurrentDictionary类是最棒的精选
  ConcurrentDictionary类的贯彻利用了细粒度锁(fine-grained locking)技术,这在八线程写入方面比选拔锁的常常的字典(也被称为粗粒度锁)

 

using System;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    static class Module
    {
        public static Task GetRandomDelay()
        {
            int delay = new Random(DateTime.Now.Millisecond).Next(1, 500);
            return Task.Delay(delay);
        }
    }
}

金沙澳门官网网址 9金沙澳门官网网址 10

Program

金沙澳门官网网址 11金沙澳门官网网址 12

金沙澳门官网网址 13金沙澳门官网网址 14

Module

5、ConcurrentBag类

Program

using System;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        //静态LocalDataStoreSlot变量
        static LocalDataStoreSlot slot;

        static void Main(string[] args)
        {
            //创建Slot
            slot = Thread.AllocateDataSlot();

            //设置TLS中的值
            Thread.SetData(slot, "hehe");

            //修改TLS的线程
            Thread th = new Thread(() =>
            {
                Thread.SetData(slot, "Mgen");
                Display();

            });

            th.Start();
            th.Join();
            Display();
        }

        //显示TLS中Slot值
        static void Display()
        {
            Console.WriteLine("{0} {1}", Thread.CurrentThread.ManagedThreadId, Thread.GetData(slot));
        }

    }
}

金沙澳门官网网址 15金沙澳门官网网址 16

本文由金沙澳门官网网址发布于电脑系统,转载请注明出处:线程安全类型,NET并行计算和并发4

关键词: