码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2017-01-19 18:26:18      阅读:224      评论:0      收藏:0      [点我收藏+]

标签:second   add   stat   using   getname   如何   mil   manage   数据   

线程本地存储

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# 线程本地存储 调用上下文 逻辑调用上下文

标签:second   add   stat   using   getname   如何   mil   manage   数据   

原文地址:http://www.cnblogs.com/lgxlsm/p/6307524.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!