.NET:线程本地存储、调用上下文、逻辑调用上下文
.NET:线程本地存储、调用上下文、逻辑调用上下文
背景返回目录
在多线程环境,如果需要将实例的生命周期控制在某个操作的执行期间,该如何设计?经典的思路是这样的:作为参数向调用栈传递,如:CommandExecuteContext、HttpContext等。好在很多平台都提供线程本地存储这种东西,下面介绍一下 .NET 提供的三种机制。
线程本地存储返回目录
代码

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6 using System.Threading.Tasks;
7 using System.Runtime.Remoting;
8
9 namespace ExecutionContextStudy
10 {
11 class ThreadDataSlotTest
12 {
13 public static void Test()
14 {
15 for (var i = 0; i < 10; i++)
16 {
17 Thread.Sleep(10);
18
19 Task.Run(() =>
20 {
21 var slot = Thread.GetNamedDataSlot("test");
22 if (slot == null)
23 {
24 Thread.AllocateNamedDataSlot("test");
25 }
26
27 if (Thread.GetData(slot) == null)
28 {
29 Thread.SetData(slot, DateTime.Now.Millisecond);
30 }
31
32 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + Thread.GetData(slot));
33 });
34 }
35
36 Console.ReadLine();
37 }
38 }
39 }

结果

说明
如果使用了线程池,最好不要使用这种存储机制了,因为线程池可能不会释放使用过的线程,导致多次执行之间可能共享数据(可以每次执行前重置线程本地存储的数据)。
调用上下文返回目录
代码

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6 using System.Threading.Tasks;
7 using System.Runtime.Remoting.Messaging;
8
9 namespace ExecutionContextStudy
10 {
11 class CallContextTest
12 {
13 public static void Test()
14 {
15 Console.WriteLine("测试:CallContext.SetData");
16 for (var i = 0; i < 10; i++)
17 {
18 Thread.Sleep(10);
19
20 Task.Run(() =>
21 {
22 if (CallContext.GetData("test") == null)
23 {
24 CallContext.SetData("test", DateTime.Now.Millisecond);
25 }
26
27 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.GetData("test"));
28 });
29 }
30
31 Console.ReadLine();
32 }
33 }
34 }

结果

说明
由上图可以知道,每次执行的数据是完全隔离的,非常符合我们的期望。但是,如果我们期望调用期间又开启了一个子线程,如何让子线程访问父线程的数据呢?这就需要使用到:“逻辑调用上下文”。
逻辑调用上下文返回目录
代码

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6 using System.Threading.Tasks;
7 using System.Runtime.Remoting.Messaging;
8
9 namespace ExecutionContextStudy
10 {
11 class ExecutionContextTest
12 {
13 public static void Test()
14 {
15 Console.WriteLine("测试:CallContext.SetData");
16 Task.Run(() =>
17 {
18 CallContext.SetData("test", "段光伟");
19 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.GetData("test"));
20
21 Task.Run(() =>
22 {
23 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.GetData("test"));
24 });
25 });
26
27 Thread.Sleep(100);
28
29 Console.WriteLine("测试:CallContext.LogicalSetData");
30 Task.Run(() =>
31 {
32 CallContext.LogicalSetData("test", "段光伟");
33 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.LogicalGetData("test"));
34
35 Task.Run(() =>
36 {
37 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.LogicalGetData("test"));
38 });
39
40 ExecutionContext.SuppressFlow();
41 Task.Run(() =>
42 {
43 Console.WriteLine("SuppressFlow 之后:" + CallContext.LogicalGetData("test"));
44 });
45
46 ExecutionContext.RestoreFlow();
47 Task.Run(() =>
48 {
49 Console.WriteLine("RestoreFlow 之后:" + CallContext.LogicalGetData("test"));
50 });
51 });
52
53 Console.ReadLine();
54 }
55 }
56 }

输出

说明
注意 ExecutionContext.SuppressFlow(); 和 xecutionContext.RestoreFlow();,它们分别能阻止传播和重置传播,默认是允许传播的。
备注返回目录
最常见的使用场景就是:为 Ioc 容器自定义生命周期管理模型。
.NET:线程本地存储、调用上下文、逻辑调用上下文的更多相关文章
- C# 线程本地存储 调用上下文 逻辑调用上下文
线程本地存储 using System; using System.Threading; using System.Threading.Tasks; namespace ConsoleAppTest ...
- 线程本地存储 ThreadLocal
线程本地存储 · 语雀 (yuque.com) 线程本地存储提供了线程内存储变量的能力,这些变量是线程私有的. 线程本地存储一般用在跨类.跨方法的传递一些值. 线程本地存储也是解决特定场景下线程安全问 ...
- 线程本地存储TLS(Thread Local Storage)的原理和实现——分类和原理
原文链接地址:http://www.cppblog.com/Tim/archive/2012/07/04/181018.html 本文为线程本地存储TLS系列之分类和原理. 一.TLS简述和分类 我们 ...
- 线程本地存储TLS(Thread Local Storage)的原理和实现——分类和原理
本文为线程本地存储TLS系列之分类和原理. 一.TLS简述和分类 我们知道在一个进程中,所有线程是共享同一个地址空间的.所以,如果一个变量是全局的或者是静态的,那么所有线程访问的是同一份,如果某一个线 ...
- ThreadLocal(线程本地存储)
1. ThreadLocal,即线程本地变量或线程本地存储. threadlocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或组件之间一些公共变量传递的 ...
- 线程本地存储(动态TLS和静态TLS)
线程本地存储(TLS) 对于多线程应用程序,如果线程过于依赖全局变量和静态局部变量就会产生线程安全问题.也就是一个线程的使用全局变量可能会影响到其他也使用此全局变量的线程,有可能会造成一定的错误,这可 ...
- Atitit usrqbg1821 Tls 线程本地存储(ThreadLocal Storage 规范标准化草案解决方案ThreadStatic
Atitit usrqbg1821 Tls 线程本地存储(ThreadLocal Storage 规范标准化草案解决方案ThreadStatic 1.1. ThreadLocal 设计模式1 1.2. ...
- 线程本地存储(Thread Local Storage, TLS)简单分析与使用
在多线程编程中, 同一个变量, 如果要让多个线程共享访问, 那么这个变量可以使用关键字volatile进行声明; 那么如果一个变量不想使多个线程共享访问, 那么该怎么办呢? 呵呵, 这个办法就是TLS ...
- Java线程本地存储ThreadLocal
前言 ThreadLocal 是一种 无同步 的线程安全实现 体现了 Thread-Specific Storage 模式:即使只有一个入口,内部也会为每个线程分配特有的存储空间,线程间 没有共享资源 ...
随机推荐
- AT&T汇编——在你开始写
不知不觉,少年将超过,计算机相关知识,学到基本上可以说是教过.毕业.所以,我们打算更深入了解自己的兴趣背着背笼.也因为它是检讨大学. 计划写的内容在: 1.汇编语言 2.C/C++语言 3.Linux ...
- 第19章 解释器模式(Interpreter Pattern)
原文 第19章 解释器模式(Interpreter Pattern) 解释器模式 导读:解释器模式,平常用的比较的少,所以在写这个模式之前在博客园搜索了一番,看完之后那叫一个头大.篇幅很长,我鼓足了劲 ...
- js 正则学习小记之NFA引擎
原文:js 正则学习小记之NFA引擎 之前一直认为自己正则还不错,在看 次碳酸钴,Barret Lee 等大神都把正则玩的出神入化后发现我只是个战五渣. 求抱大腿,求大神调教. 之前大致有个印象,正 ...
- Leetcode:convert_sorted_array_to_binary_search_tree
一. 称号 排序后的数组成二叉搜索树. 二. 分析 BST的中序遍历是一个sorted-array,再构造回去成一个BST,先将中间的元素作为根节点,这个节点的左右各自是左子树和右子树 ...
- OS和android游戏纹理优化和内存优化(cocos2d-x)
注:原文地址不详! 1.2d游戏最占内存的无疑是图片资源. 2.cocos2d-x不同平台读取纹理的机制不同. ios以下使用CGImage,android和windows下是直接调用png库.我測试 ...
- 今天才知道css hack是什么
先来个冷笑话:一晚下班回家,一民警迎面巡逻而来.突然对我大喊:站住! 民警:int类型占几个字节? 我:4个. 民警:你可以走了. 我感到很诧异. 我:为什么问这样的问题? 民警:深夜还在街上走,寒酸 ...
- Java数据结构与算法(2) - ch03排序(冒泡、插入和选择排序)
排序需要掌握的有冒泡排序,插入排序和选择排序.时间为O(N*N). 冒泡排序: 外层循环从后往前,内存循环从前往后到外层循环,相邻数组项两两比较,将较大的值后移. 插入排序: 从排序过程的中间开始(程 ...
- Uva 409-Excuses, Excuses!(串)
Judge Ito is having a problem with people subpoenaed for jury duty giving rather lame excuses in ord ...
- .net mvc mssql easyui treegrid
效果图 数据图 可以看到 这里是根据 MenuNo 来 分级别的,支持 无限极,第一级是 01 ,第二级就是 01XX ,第三级 就是 01XXOO.类似 id.pid ,Ztree 里面 也是这 ...
- android详细信息java.util.ConcurrentModificationException变态
在今天做android当项目,我遇到了这个异常,好吧.其实最不寻常遇到异常IllegalstateException.它们与我们的硬件连接SDK抛出,我想折磨学生阿玉啊.扯远了. 今天,我想回到这个异 ...