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

  • 相关阅读:
    014.Nginx跨域配置
    013.Nginx动静分离
    附002.Nginx代理相关模块解析
    附001.Nginx location语法规则
    016.Nginx HTTPS
    015.Nginx重定向
    Blazor带我重玩前端(四)
    数据结构中的树(二叉树、二叉搜索树、AVL树)
    Flask前后端分离项目案例
    LeetCode-位运算相关题解
  • 原文地址:https://www.cnblogs.com/lgxlsm/p/6307524.html
Copyright © 2020-2023  润新知