-- 多线程下函数调用链中传递数据的处理类: CallContext
【官网】:https://docs.microsoft.com/zh-cn/dotnet/api/system.runtime.remoting.messaging.callcontext?redirectedfrom=MSDN&view=netframework-
应用场景
当需要提供与执行代码路径一起传送的属性集(通俗说: 需要在代码调用链环境下传递数据)时可以使用CallContext。基础资源
.net framework下依赖System.Runtime.Remoting.Messaging.CallContext ,.net core下需自行实现(本文已包含相关实现代码)
使用须知
CallContext 专用集合对象,它类似于方法调用的线程本地存储,并提供对每个逻辑执行线程唯一的数据槽。 不会在其他逻辑线程上跨调用上下文共享槽。 CallContext当对象向下移动并备份执行代码路径,并沿着路径按各个对象检查时,可以将对象添加到中。
配置步骤
【关于System.Runtime.Remoting.Messaging.CallContext的注意事项】
1、GetData、SetData只能用于单线程环境,如果发生了线程切换,存储的数据也会随之丢失
2、可以用于同一线程中的不同地方,传递数据。
3. FreeNamedDataSlot只能清除当前线程的数据槽,不能清除子线程的数据槽;
4、LogicalSetData、LogicalGetData可用于在多线程环境下传递数据;
5、FreeNamedDataSlot清除当前线程,之前已经运行子任务,不受影响.
6. 对于LogicalSetData, 只能在调用链上自上而下设置会生效,反向不生效。
常见问题
快速入门
A).net framework下CallContext的应用。
a1)对System.Runtime.Remoting.Messaging.CallContext的调用及线程内数据槽的释放。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace DonetFrm.Test.Demo
{
/// <summary>
/// author: http://config.net.cn
/// project site:https://github.com/configlab/ResearchNotes-Demo
/// description:use CallContext in .net framework with System.Runtime.Remoting.Messaging.CallContext
/// create date: 2021-10-6
/// </summary>
public class CallContextTest_Framework
{
public void Test()
{
CallContext.LogicalSetData("entry_method", "test");
Console.WriteLine($"debug-main-1:threadId={Thread.CurrentThread.ManagedThreadId},entry_method={CallContext.LogicalGetData("entry_method")}");
Task _task = new Task(() => {
CallContext.LogicalSetData("set_from_task", "true");
Console.WriteLine($"debug-task-1:threadId={Thread.CurrentThread.ManagedThreadId},entry_method={CallContext.LogicalGetData("entry_method")}");
CallContext.FreeNamedDataSlot("entry_method");
Console.WriteLine($"debug-task-2:threadId={Thread.CurrentThread.ManagedThreadId},entry_method={CallContext.LogicalGetData("entry_method")}");
});
_task.Start();
new Thread(new ThreadStart(() => {
CallContext.LogicalSetData("set_from_subthread", "true");
Console.WriteLine($"debug-subthread-1:threadId={Thread.CurrentThread.ManagedThreadId},entry_method={CallContext.LogicalGetData("entry_method")}");
CallContext.FreeNamedDataSlot("entry_method");
Console.WriteLine($"debug-subthread-2:threadId={Thread.CurrentThread.ManagedThreadId},entry_method={CallContext.LogicalGetData("entry_method")}");
})).Start();
Thread.Sleep(5000);
Console.WriteLine($"debug-main-2:threadId={Thread.CurrentThread.ManagedThreadId},entry_method={CallContext.LogicalGetData("entry_method")},set_from_task={CallContext.GetData("set_from_task")},set_from_subthread={CallContext.GetData("set_from_subthread")}");
}
}
}
【效果如图】
B).net core下CallContext的应用。
b1)自定义实现的CallContext 源码。
using System;
using System.Collections.Concurrent;
using System.Threading;
namespace ConfigLab.CallContext
{
/// author: http://config.net.cn
/// project site:https://github.com/configlab/ResearchNotes-Demo
/// description:Provides a way to set contextual data that flows with the call and async context of a test or invocation.
/// create date: 2021-10-6
/// refer: https://www.cazzulino.com/callcontext-netstandard-netcore.html
public static class CallContext
{
static ConcurrentDictionary<string, AsyncLocal<object>> state = new ConcurrentDictionary<string, AsyncLocal<object>>();
/// <summary>
/// Stores a given object and associates it with the specified name.
/// </summary>
/// <param name="name">The name with which to associate the new item in the call context.</param>
/// <param name="data">The object to store in the call context.</param>
public static void SetData(string name, object data) =>
state.GetOrAdd(name, _ => new AsyncLocal<object>()).Value = data;
/// <summary>
/// Retrieves an object with the specified name from the <see cref="CallContext"/>.
/// </summary>
/// <param name="name">The name of the item in the call context.</param>
/// <returns>The object in the call context associated with the specified name, or <see langword="null"/> if not found.</returns>
public static object GetData(string name) =>
state.TryGetValue(name, out AsyncLocal<object> data) ? data.Value : null;
}
}
b2)基于自定义实现的CallContext的应用。
![]()
[附:本文源码地址]
https://github.com/configlab/ResearchNotes-Demo