1月25日总结

问题的由来是在.NET高级调试训练营第十期分享ThreadStatic底层玩法的时候,有朋友提出了AsyncLocal是如何实现的,虽然做了口头上的表述,但总还是会不具体,所以觉得有必要用文字+图表的方式来系统的说一下这个问题。
二:AsyncLocal 线程间传值

  1. 线程间传值途径

在 C# 编程中实现多线程以及线程切换的方式大概如下三种:

Thread
Task
await,async

这三种场景下的线程间传值有各自的实现方式,由于篇幅限制,先从 Thread 开始聊吧。本质上来说 AsyncLocal 是一个纯托管的C#玩法,和 coreclr,Windows 没有任何关系。
2. Thread 小例子

为了方便讲述,先来一个例子看下如何在新Thread线程中提取 _asyncLocal 中的值,参考代码如下:

internal class Program
{
    static AsyncLocal<int> _asyncLocal = new AsyncLocal<int>();

    static void Main(string[] args)
    {
        _asyncLocal.Value = 10;

        var t = new Thread(() =>
        {
            Console.WriteLine($"Tid={Thread.CurrentThread.ManagedThreadId}, AsyncLocal value: {_asyncLocal.Value},");
            Debugger.Break();
        });

        t.Start();

        Console.ReadLine();
    }
}

从截图看 tid=7 线程果然拿到了 主线程设置的 10 ,哈哈,是不是充满了好奇心?接下来逐一分析下吧。
3. 流转分析

首先观察下 _asyncLocal.Value = 10 在源码层做了什么,参考代码如下:

public T Value
{
    set
    {
        ExecutionContext.SetLocalValue(this, value, m_valueChangedHandler != null);
    }
}

internal static void SetLocalValue(IAsyncLocal local, object newValue, bool needChangeNotifications)
{
    ExecutionContext executionContext = Thread.CurrentThread._executionContext;

    Thread.CurrentThread._executionContext = new ExecutionContext(asyncLocalValueMap, array, flag2));
}

从源码中可以看到这个 10 最终封印在 Thread.CurrentThread._ex

posted @ 2024-01-25 18:11  lmyyyy  阅读(10)  评论(0)    收藏  举报