zoukankan      html  css  js  c++  java
  • 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();,它们分别能阻止传播和重置传播,默认是允许传播的。

  • 相关阅读:
    假期学习总结2-14
    假期学习总结2-13
    假期总结2-12
    假期总结2-11
    读人月神话
    冲刺第五天 11.29 THU
    冲刺第四天 11.28 WED
    冲刺第三天 11.27 TUE
    冲刺第二天 11.26 MON
    冲刺第一天 11.23 FRI
  • 原文地址:https://www.cnblogs.com/lgxlsm/p/6307524.html
Copyright © 2011-2022 走看看