【问题标题】:What are best practices for using thread local storage in .NET?在 .NET 中使用线程本地存储的最佳实践是什么?
【发布时间】:2025-12-05 10:30:01
【问题描述】:

我的应用程序中有一个要求,我认为可以通过使用线程本地存储来满足,但我想知道这是否是最好避免的事情之一。

我已经阅读了一些关于这个主题的文章:

http://www.dotnetcoders.com/web/Articles/ShowArticle.aspx?article=58

http://msdn.microsoft.com/en-us/library/system.threadstaticattribute(vs.80).aspx

我知道如何使用它,我只是想知道我是否应该使用它。

有什么建议和注意事项吗?

[编辑]

这是用例:

我通过一些方法汇集所有数据访问,这些方法对每个查询进行大量记录。我记录的一件事是命令文本的完整转储,其中填充了命令,以便我可以简单地从跟踪日志中直接复制粘贴到 Sql Management Studio 中。

在我的 web 应用程序中的 global.asax 中,当我遇到未处理的异常时,我会向管理员发送尽可能多的信息的电子邮件。当我收到 SqlException 时,我想将那个 sql 命令转储文本放入这封电子邮件中,这将节省我在页面因查询而崩溃时挖掘跟踪日志的时间。

我不想更改我的数据访问类的方法签名,这样我就可以将一些引用一直传递到堆栈中,只是为了在我遇到异常时将其取出。我在想也许 TLS 是放置“lastsqlcommand”之类的好地方,但这看起来不是一个可行的解决方案。

【问题讨论】:

  • 我一直避免使用线程本地存储,并找到了另一种方法来做同样的事情。我的想法一直是线程本地存储可能比直接访问慢(不确定这是否正确)。我也很好奇其他人的想法。

标签: .net multithreading thread-local


【解决方案1】:

asp.net 应用程序的一个陷阱:单个请求的处理可能会切换线程,即如果同一会话中有并行请求。因此,您在 HttpApplication.PostRequireRequestState 事件之前放入 TLS 的任何内容都可能稍后不会出现,因为您在不同的线程上。

[由提问者编辑]

对于我的特定用例,我最终将键值对添加到 SqlException.Data 字典中,然后在记录异常详细信息时检索该字典。这给了我希望使用线程本地存储的功能。

【讨论】:

  • 这正是我想要的。我怀疑在这种情况下它可能不可靠。谢谢。
  • 这是一个旧答案,但需要澄清一点:ASP.NET 仅在非常特定的场景中切换线程。最大的是使用异步 IO 方法——参见例如Lhotka 和 Guthrie 讨论:lhotka.net/WeBlog/…
【解决方案2】:

线程本地存储是修复在线程之前设计并使用大量全局变量和静态的库的一种快速方法。这是 C 标准库在不更改其接口的同时实现线程安全的方式(在内部,许多函数使用静态缓冲区)。

一般来说,这对这个目的是有好处的。如果您必须在多线程环境中拥有全局数据,那么线程本地存储是一个不错的选择。一个常见的原因是您正在调用一个第三方函数,该函数在同一个堆栈帧中回调您,但没有为您提供传递额外信息的钩子——当您尝试将较旧的 C 库包装在.NET。

【讨论】:

    【解决方案3】:

    通过示例查看新的 .net 4 ThreadLocal<T> 类,更多信息 here

    【讨论】: