本文介绍了为什么逻辑调用上下文不跨线程传播?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个奇怪的问题,逻辑调用上下文没有传播到应用程序中的线程.

I have a weird problem with logical call contexts not propagating to threads in my application.

在此示例中,线程(在设置逻辑调用上下文数据之前创建的)不会获取新值:

In this sample, the thread (created before logical call context data is set) does not pick up the new value:

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<string> _messages;
        private readonly AutoResetEvent _waitHandle;
        private bool _terminate;
        private bool _messageMonitoringActive;

        public MessageDispatcher()
        {
            _messages = new ConcurrentQueue<string>();
            _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")}");
                }
        }
    }
}

对于在创建的线程内进行的所有调用,未从刚刚设置的上下文变量中采用调用上下文数据.为什么会这样?

For all calls made within the created thread, the call context data is not adopted from the just set context variable. Why is that?

在我的应用程序中,我无法在实例化时设置逻辑调用上下文变量(这是在启动时通过IoC(它是WebAPI堆栈)通过IoC完成的),而只能在每次调用时进行.

In my application, I can't set logical call context variable at instantiation (which is done via IoC on startup (it's a WebAPI stack)), but only on each invocation.

推荐答案

MSDN文档指出

还有

仅阅读文档,您就会认为这种情况将行不通.这对于SetDataGetData方法是正确的;如果在一个线程上使用SetData,则必须在同一线程上使用GetData才能取回数据.

Just from reading the documentation, you'd think that this scenario just won't work. And that's true for the SetData and GetData methods; if you use SetData on one thread, you have to use GetData on the same thread to get the data back out.

但是,有一个例外.您已经在使用的SetLogicalDataGetLogicalData.它们被设计为通过逻辑线程"流过上下文,即通过同一线程传递到子线程.

There is an exception, though; SetLogicalData and GetLogicalData, which you're already using. These are designed to flow context through "logical threads", i.e. across the same thread and through to child threads.

您的方法存在的问题是,您试图在创建并启动子线程后 传递数据,这是行不通的.如果您移动

The problem with your approach is that you're trying to pass data after the child thread has been created and started, which won't work. If you move

CallContext.LogicalSetData("myvar", "Logical call context variable");

上方

var dispatcher = new MessageDispatcher();

即在创建和启动线程之前(在MessageDispatcher构造函数中).您会看到您正确获得了价值.

i.e. before the thread is created and started (in the MessageDispatcher constructor). You'll see that you get the value out correctly.

换句话说;您需要在创建和启动子线程之前确保已设置所有数据.

In other words; you need to make sure all data is set before you create and start the child thread.

这篇关于为什么逻辑调用上下文不跨线程传播?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-22 21:00
查看更多