我有一个奇怪的问题,逻辑调用上下文没有传播到我的应用程序中的线程.
在此示例中,线程(在设置逻辑调用上下文数据之前创建)不会获取新值:
class Program
{
static void Main(string[] args)
{
var dispatcher = new MessageDispatcher();
//Logical call context data not set yet
Console.WriteLine($"Main: {Thread.CurrentThread.ManagedThreadId}: {CallContext.LogicalGetData("myvar")}"); // Main logical call context data is not set yet = Null
dispatcher.Broadcast("a string"); // logical call context data is still not set yet = Null
//Logical call context data is set now
CallContext.LogicalSetData("myvar", "Logical call context variable");
Console.WriteLine($"Main: {Thread.CurrentThread.ManagedThreadId}: {CallContext.LogicalGetData("myvar")}"); // Main logical call context data is set = return value
dispatcher.Broadcast("a string"); // Logical call context data is set and should return the data set above?
Console.ReadLine();
}
public class MessageDispatcher
{
private readonly ConcurrentQueue _messages;
private readonly AutoResetEvent _waitHandle;
private bool _terminate;
private bool _messageMonitoringActive;
public MessageDispatcher()
{
_messages = new ConcurrentQueue();
_waitHandle = new AutoResetEvent(false);
var thread = new Thread(MonitorCollection);
thread.Start();
}
public void Broadcast(string message)
{
_messages.Enqueue(message);
_waitHandle.Set();
}
private void MonitorCollection()
{
_waitHandle.WaitOne();
string message;
while (_messages.TryDequeue(out message))
{
Console.WriteLine(
$"{message}: {Thread.CurrentThread.ManagedThreadId}: {CallContext.LogicalGetData("myvar")}");
}
}
}
}
对于在创建的线程内进行的所有调用,不会从刚刚设置的上下文变量中采用调用上下文数据.这是为什么?
在我的应用程序中,我无法在实例化时设置逻辑调用上下文变量(这是在启动时通过IoC完成的(它是一个WebAPI堆栈)),但仅限于每次调用.
在MSDN文档指出,
CallContext是一个专门的集合对象,类似于方法调用的线程本地存储,并提供对每个逻辑执行线程唯一的数据槽.插槽不在其他逻辑线程上的调用上下文之间共享.可以将对象添加到CallContext中,因为它向下移动并备份执行代码路径,并通过路径上的各种对象进行检查.
还有那个
CallContext中的所有方法都是静态的,并且在当前Thread中的调用上下文中操作.
只是阅读文档,你会认为这种情况不起作用.而这对于真正SetData
和GetData
方法; 如果你SetData
在一个线程上使用,你必须GetData
在同一个线程上使用才能恢复数据.
但是有一个例外; SetLogicalData
而且GetLogicalData
,你已经在使用它了.这些设计用于通过"逻辑线程"流动上下文,即跨越相同的线程并通过子线程.
您的方法的问题是您在创建和启动子线程后尝试传递数据,这将无法正常工作.如果你搬家
CallContext.LogicalSetData("myvar", "Logical call context variable");
以上
var dispatcher = new MessageDispatcher();
即在创建和启动线程之前(在MessageDispatcher
构造函数中).你会看到你正确地获得了价值.
换一种说法; 您需要确保在创建和启动子线程之前设置所有数据.