首页 > 代码库 > C# 线程本地存储 调用上下文 逻辑调用上下文

C# 线程本地存储 调用上下文 逻辑调用上下文

线程本地存储

using System;using System.Threading;using System.Threading.Tasks;namespace ConsoleAppTest{    class Program    {        static void Main(string[] args)        {            ThreadDataSlotTest.Test();        }    }    /// <summary>    /// 线程本地存储     /// </summary>    class ThreadDataSlotTest    {        public static void Test()        {            for (var i = 0; i < 10; i++)            {                Thread.Sleep(10);                Task.Run(() =>                {                    var slot = Thread.GetNamedDataSlot("test");                    if (slot == null)                    {                        Thread.AllocateNamedDataSlot("test");                    }                    if (Thread.GetData(slot) == null)                    {                        Thread.SetData(slot, DateTime.Now.Millisecond);                    }                    Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + Thread.GetData(slot));                });            }            Console.ReadLine();        }    }}

技术分享

如果使用了线程池,最好不要使用这种存储机制了,因为线程池可能不会释放使用过的线程,导致多次执行之间可能共享数据(可以每次执行前重置线程本地存储的数据)。

调用上下文

using System;using System.Runtime.Remoting.Messaging;using System.Threading;using System.Threading.Tasks;namespace ConsoleAppTest{    class Program    {        static void Main(string[] args)        {            CallContextTest.Test();        }    }    /// <summary>    /// 调用上下文     /// </summary>    class CallContextTest    {        public static void Test()        {            if (CallContext.GetData("test") == null)            {                CallContext.SetData("test", "CallContext.SetData");            }            for (var i = 0; i < 10; i++)            {                Thread.Sleep(10);                Task.Run(() =>                {                    if (CallContext.GetData("test") == null)                    {                        CallContext.SetData("test", DateTime.Now.Millisecond);                    }                    Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.GetData("test"));                });            }            Console.ReadLine();        }    }}

 

技术分享

由上图可以知道,每次执行的数据是完全隔离的,非常符合我们的期望。但是,如果我们期望调用期间又开启了一个子线程,如何让子线程访问父线程的数据呢?这就需要使用到:“逻辑调用上下文”。

逻辑调用上下文

using System;using System.Runtime.Remoting.Messaging;using System.Threading;using System.Threading.Tasks;namespace ConsoleAppTest{    class Program    {        static void Main(string[] args)        {            ExecutionContextTest.Test();        }    }    /// <summary>    /// 调用上下文     /// </summary>    class ExecutionContextTest    {        public static void Test()        {            Console.WriteLine("测试:CallContext.SetData");            Task.Run(() =>            {                CallContext.SetData("test", "wolf");                Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.GetData("test"));                Task.Run(() =>                {                    Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.GetData("test"));                });            });            Thread.Sleep(100);            Console.WriteLine("测试:CallContext.LogicalSetData");            Task.Run(() =>            {                CallContext.LogicalSetData("test", "wolf");                Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.LogicalGetData("test"));                Task.Run(() =>                {                    Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.LogicalGetData("test"));                });                ExecutionContext.SuppressFlow();                Task.Run(() =>                {                    Console.WriteLine("SuppressFlow 之后:" + CallContext.LogicalGetData("test"));                });                ExecutionContext.RestoreFlow();                Task.Run(() =>                {                    Console.WriteLine("RestoreFlow 之后:" + CallContext.LogicalGetData("test"));                });            });            Console.ReadLine();        }    }}

技术分享

注意 ExecutionContext.SuppressFlow(); 和 xecutionContext.RestoreFlow();,它们分别能阻止传播和重置传播,默认是允许传播的。

 

C# 线程本地存储 调用上下文 逻辑调用上下文