C多线程tss_t

tss_t tss_key,为什么不同的线程,使用同一个tss_key,得到的是不同的存储?

这是一个非常好的问题,它触及了线程特定存储(TSS)机制的核心设计思想。

简单来说,答案是:tss_key 本身不存储数据,它只是一个“钥匙”或“索引”,系统利用这把钥匙为每个线程在内部维护了一个独立的“存储槽”。

我们可以用一个生动的比喻来理解:

储物柜比喻

想象一个大型健身房(这代表你的整个程序),里面有很多会员(代表线程)。

  1. tss_create(&tss_key, destructor) - 创建储物柜系统
    • 健身房前台创建了一套储物柜系统(tss_key 就是这个系统的唯一标识符/总钥匙)。
    • 他们还规定了清理规则(destructor):当会员离开时,必须清空他使用的所有柜子,否则健身房会帮他清理并可能收取费用(防止内存泄漏)。
  2. tss_set(tss_key, value) - 存放物品
    • 会员A(线程A)来了,他想存包。他告诉前台:“用这个储物柜系统tss_key),把我的包(value)存到属于我的那个柜子里。”
    • 前台就会在系统中找到专门为会员A分配的那个空柜子,把包放进去。
    • 会员B(线程B)也来存包,他也使用同一个储物柜系统tss_key),但前台会把他的包放到专门为会员B分配的另一个柜子里。
  3. tss_get(tss_key) - 取回物品
    • 会员A later回来取包,他说:“用这个储物柜系统tss_key),把我的柜子里的东西给我。” 前台就会把他柜子里的包拿给他。
    • 会员B来取他的包,前台会从另一个柜子里拿出他的东西。

关键点在于:虽然所有人都使用同一个“储物柜系统”(tss_key),但这个系统内部为每个会员(线程)都分配了专属的、私有的存储空间tss_key 只是用来标识“要使用哪个系统”,而系统内部自动将“系统”和“线程”结合起来,定位到正确的物理存储位置。


技术层面的解释

在技术实现上,C11 运行时库(或操作系统线程库)会维护一个内部数据结构,通常可以理解为:

  • 一个全局的 TSS 键数组tss_key 是这个数组的一个索引。每个键在创建时会记录它的销毁函数等信息。
  • 每个线程都有一个 TSD(Thread-Specific Data)指针数组:这个数组与全局的 TSS 键数组一一对应。数组的每个元素是一个 void* 指针,用于存储该线程对应这个键的数据。

当你调用 tss_set(tss_key, value) 时,实际发生的是:

  1. 获取当前线程的 TSD 指针数组。
  2. 将 value 存储到该数组的第 tss_key 个位置。

当你调用 tss_get(tss_key) 时,实际发生的是:

  1. 获取当前线程的 TSD 指针数组。
  2. 返回该数组第 tss_key 个位置存储的值。

因此,tss_key 就像一个二维坐标的 X 轴(键索引),而线程ID是 Y 轴(线程索引)。系统通过 (线程ID, tss_key) 这个唯一的坐标对来定位到每个线程独有的数据存储单元。

总结

组件角色类比
tss_key标识符/索引储物柜系统的ID号
系统内部数据结构将键映射到线程局部存储储物柜本身,为每个会员分配了独立格间
tss_set(key, val)为当前线程在指定键位置存储值会员A把包放进自己的格子
tss_get(key)为当前线程获取指定键位置的值会员A从自己的格子取出包

这种设计使得 tss_key 可以作为一个全局的、共享的“句柄”,而每个线程通过这个句柄访问到的却是自己独立的数据,完美地实现了“一把钥匙,多个保险箱”的效果。

tss_t tss_key,为什么要设计成可以让多个线程都使用一个tss_key?

这是一个非常深刻的设计问题。将 tss_key 设计成可被多个线程共享使用,而不是为每个线程创建独立的键,是线程特定存储(TSS)机制的核心和精妙之处。

这样做的根本原因是:tss_key 的目的不是标识线程,而是标识一种“数据类型”或“数据槽位”

我们可以从以下几个关键角度来理解这个设计的必要性和优势:

1. 标识“数据类型”,而非“线程”

想象一下,你是一个库的作者(比如实现一个数据库连接池或一个数学计算库)。你需要在库内部为每个线程存储一些上下文信息(例如,数据库连接对象、随机数生成器状态、错误码等)。

  • 你的需求是:“我需要一个地方来存放‘我的库的上下文’ 这个数据。”
  • 而不是:“我需要为每个线程都创建一个全新的、不同的数据类型。”

所有线程都需要访问同一种数据——“我的库的上下文”。tss_key 就是这个“数据类型”的全局唯一标识符。每个线程通过这个相同的“钥匙”,去打开属于自己的那把“锁”(即获取自己线程的上下文数据)。

如果每个线程都有一个独立的键,那么线程之间就无法共享对同一种数据类型的引用,整个机制就失去了意义。

2. 实现“声明-使用”分离,代码更清晰、可维护

这种设计允许“键”的创建者(通常是库的初始化代码)和“键”的使用者(各个工作线程)分离。

  • 初始化阶段(主线程)tss_create(&library_context_key, destroy_context);
    • 这里创建了一个键,并注册了销毁函数。这相当于声明:“我们程序中将存在一种叫做‘library_context’的线程局部数据,当线程退出时,请用 destroy_context 函数来清理它。”
  • 使用阶段(任何线程)c// 在任何线程中,都可以这样使用 my_library_context_t* ctx = tss_get(library_context_key); if (ctx == NULL) { ctx = create_context(); // 第一次使用时初始化 tss_set(library_context_key, ctx); } // ... 使用 ctx ...
    • 所有线程都使用同一个 library_context_key 来获取和设置属于自己的上下文。代码简洁统一,不需要为每个线程传递不同的键值。

3. 高效的资源管理和生命周期控制

这是最关键的优势之一。销毁函数(destructor)的注册是与 tss_key 绑定的,而不是与某个特定线程绑定的。

  • 场景:你的库使用 tss_create 创建了一个键 key_for_conn,并注册了 close_connection 作为销毁函数。
  • 工作流程
    1. 线程A调用 tss_set(key_for_conn, db_conn_A),将它的数据库连接与该键绑定。
    2. 线程B调用 tss_set(key_for_conn, db_conn_B),将它的数据库连接与同一个键绑定。
    3. 当线程A结束时,系统自动检查它是否为 key_for_conn 设置了值。如果有,就调用 close_connection(db_conn_A)
    4. 当线程B结束时,系统同样检查并调用 close_connection(db_conn_B)

如果每个线程有自己的键,那么注册销毁函数将变得极其复杂甚至不可能,因为你无法在创建键的时候预知未来所有线程的行为。

4. 与 thread_local 的对比

特性tss_t / tss_key (动态TSS)thread_local (静态TLS)
标识符tss_key 是一个运行时的、动态的句柄。变量本身在编译/链接时就已经确定。
灵活性极高。可以在运行时决定需要多少种线程局部数据,并动态创建和销毁。非常适合库的开发。较低。需要在编码时就声明好所有线程局部变量。
资源管理强大。支持为每种数据类型注册销毁函数,自动清理资源(如关闭文件、释放内存)。薄弱。不支持自动销毁函数。如果变量是指针,需要手动管理内存,容易泄漏。
使用场景实现库、管理动态资源、需要精细控制生命周期的场景。应用层编程、已知且固定的线程局部数据。

总结

将 tss_key 设计为可被多个线程共享,是为了实现一个统一、高效、可管理的线程特定数据注册和访问系统

  • tss_key 是数据类型的全局标识符
  • 系统内部 为每个线程维护了一个与这些键对应的值数组
  • 组合起来(线程, tss_key) 这个唯一的组合才最终定位到一个具体的数据存储单元。

这种设计使得编写需要维护线程上下文的库变得异常简洁和安全,是多线程库开发中的基石之一。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇
error: Content is protected !!