C# 线程本地存储 调用上下文 逻辑调用上下文
Posted 积少成多
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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(); 和 ExecutionContext.RestoreFlow();,它们分别能阻止传播和重置传播,默认是允许传播的。
以上是关于C# 线程本地存储 调用上下文 逻辑调用上下文的主要内容,如果未能解决你的问题,请参考以下文章