c# ConditionalWeakTable 在并发场景下的应用

阿浩吖_9438

阿浩吖_9438

2026-01-23

405人浏览

原创

ConditionalWeakTable 是线程安全的,但仅限于自身字典操作;其方法内部加锁或使用原子操作,可防止数据结构损坏,适用于 RuntimeHelpers、WPF 附加属性等底层场景,但回调函数需幂等且避免非线程安全操作。

c# conditionalweaktable 在并发场景下的应用

ConditionalWeakTable 是线程安全的,但不等于“自动解决所有并发问题”

ConditionalWeakTable 的所有公开方法(Add、GetValue、TryGetValue 等)内部都加了锁或使用了原子操作,因此**多线程调用不会导致数据结构损坏或崩溃**。这是它被设计用于 RuntimeHelpers.GetOrCreateObjectData、WPF 的附加属性、EF Core 的实体跟踪等底层场景的根本原因。

但要注意:它的线程安全仅限于自身字典操作。如果你在 createValueCallback 里做非线程安全操作(比如修改共享静态变量、访问未同步的集合),依然会出问题。

  • GetValue 的回调函数可能被多个线程同时触发——即使键相同,只要尚未完成首次创建,多个线程都可能进入回调
  • 回调执行期间,其他线程对同一键的 GetValue 会阻塞等待;但不同键之间完全无干扰
  • 没有内置的“只让第一个线程执行回调,其余等待结果”的去重逻辑——它靠内部锁实现串行化,不是靠 CAS 或 double-check

用 GetValue 创建单例式附加状态时,回调必须幂等

典型场景是给任意对象(比如 Stream 或自定义类实例)附着一个线程本地或生命周期绑定的辅助对象,又不想阻止原对象被回收。这时常配合 GetValue 使用:

var table = new ConditionalWeakTable<myclass lazy>>();
var resource = table.GetValue(obj, _ => new Lazy<expensiveresource>(() => new ExpensiveResource()));</expensiveresource></myclass>

上面写法看似简洁,但有隐患:Lazy 的构造本身不执行初始化,而 resource.Value 第一次访问才创建实例——这意味着多个线程仍可能并发进入 new ExpensiveResource(),除非你用 LazyThreadSafetyMode.ExecutionAndPublication(默认就是它)。

  • 更稳妥的做法是直接在回调里返回已构建好的对象,或者确保构造逻辑本身可重入
  • 不要在回调中调用 lock 去保护外部资源——这容易引发死锁,因为 GetValue 内部已有锁
  • 若需延迟初始化 + 线程安全,优先用 Lazy 包一层,且显式指定 LazyThreadSafetyMode.ExecutionAndPublication

别把它当 ConcurrentDictionary 用

ConditionalWeakTable 和 ConcurrentDictionary 完全不是一回事:

Livestream Script Generator
Livestream Script Generator

直播带货脚本:话术、节奏、互动、促单。适用于主播、电商运营、MCN机构。

下载
  • 前者 key 是弱引用(key 对象被 GC 后,对应条目自动消失),后者是强引用
  • 前者不支持枚举(Keys、Values、GetEnumerator 全部抛 NotSupportedException),后者支持
  • 前者没有 Count 属性,无法知道当前挂了多少关联项;后者有
  • 前者不能手动删除(没 Remove 方法),只能等 key 被回收;后者可主动清理

如果你需要“带弱引用语义的并发字典”,ConditionalWeakTable 不满足需求——得自己封装,比如用 ConcurrentDictionary, TValue> 并定期清理失效引用,但这会失去 ConditionalWeakTable 的自动清理优势。

调试时看不到内容,别以为没生效

在 Visual Studio 调试器里,ConditionalWeakTable 的字段(如 m_tables)是私有的、内部结构复杂,且调试器不会触发其弱引用遍历逻辑。所以断点停住后展开对象,大概率看到空的 Keys 或报错“not supported”。

验证是否生效,唯一可靠方式是:

  • 写单元测试,用 GC.Collect() + GC.WaitForPendingFinalizers() 后检查原 key 是否还能通过 TryGetValue 拿到值
  • 在回调里打日志,确认是否被调用、调用次数是否符合预期(尤其高并发下)
  • 用内存分析工具(如 dotMemory)查看是否存在意外的强引用链阻止 key 回收

它的行为藏在 GC 和运行时协作深处,表面安静,实际很忙。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

回调函数 stream c#

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
resource是什么文件
resource是什么文件

Resource文件是一种特殊类型的文件,它通常用于存储应用程序或操作系统中的各种资源信息。它们在应用程序开发中起着关键作用,并在跨平台开发和国际化方面提供支持。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.12.20

320

3

counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.11.20

3968

5

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

2025.08.29

4748

10

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

2025.10.23

924

4

treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.12.01

2941

7

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

2025.12.22

416

20

深入理解算法:高效算法与数据结构专题
深入理解算法:高效算法与数据结构专题

本专题专注于算法与数据结构的核心概念,适合想深入理解并提升编程能力的开发者。专题内容包括常见数据结构的实现与应用,如数组、链表、栈、队列、哈希表、树、图等;以及高效的排序算法、搜索算法、动态规划等经典算法。通过详细的讲解与复杂度分析,帮助开发者不仅能熟练运用这些基础知识,还能在实际编程中优化性能,提高代码的执行效率。本专题适合准备面试的开发者,也适合希望提高算法思维的编程爱好者。

2026.01.06

437

22

C++ 数据结构与算法实现教程合集
C++ 数据结构与算法实现教程合集

以 C++ 为实现语言,系统讲解核心数据结构与算法,涵盖链表(单链表/双链表/环检测)、栈与队列(单调栈/优先队列)、二叉树(遍历/BST/AVL/红黑树)、哈希表(开地址法/链地址法)、图(邻接表/BFS/DFS/Dijkstra/拓扑排序)、常见排序算法(快排/归并/堆排/计数排序)的实现与复杂度分析,同时分享 LeetCode 刷题技巧、竞赛编程常用模板(二分/前缀和/滑动窗口/动态规划),帮助开发者夯实算法基础。

2026.05.09

512

25

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

2023.08.10

4898

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP进阶篇-函数(玉女心经版)
PHP进阶篇-函数(玉女心经版)

共12课时 | 2.1万人学习

最好理解的Promise教程
最好理解的Promise教程

共10课时 | 1.3万人学习

Go-Zero goctl安装与使用手册
Go-Zero goctl安装与使用手册

共0课时 | 0人学习