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();,它們分別能阻止傳播和重置傳播,默認是允許傳播的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM