惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Jina AI
Jina AI
I
Intezer
F
Fortinet All Blogs
S
SegmentFault 最新的问题
罗磊的独立博客
V
Visual Studio Blog
V
V2EX
大猫的无限游戏
大猫的无限游戏
The Cloudflare Blog
J
Java Code Geeks
美团技术团队
B
Blog
U
Unit 42
F
Full Disclosure
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
P
Privacy International News Feed
G
Google Developers Blog
雷峰网
雷峰网
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Privacy & Cybersecurity Law Blog
T
Tor Project blog
酷 壳 – CoolShell
酷 壳 – CoolShell
量子位
GbyAI
GbyAI
S
Schneier on Security
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Google DeepMind News
Google DeepMind News
D
Darknet – Hacking Tools, Hacker News & Cyber Security
L
LINUX DO - 热门话题
Recorded Future
Recorded Future
D
Docker
博客园 - 聂微东
Project Zero
Project Zero
Know Your Adversary
Know Your Adversary
P
Palo Alto Networks Blog
K
Kaspersky official blog
Martin Fowler
Martin Fowler
H
Hackread – Cybersecurity News, Data Breaches, AI and More
L
Lohrmann on Cybersecurity
A
Arctic Wolf
T
The Blog of Author Tim Ferriss
Microsoft Security Blog
Microsoft Security Blog
T
Threat Research - Cisco Blogs
T
The Exploit Database - CXSecurity.com
V
Vulnerabilities – Threatpost
Simon Willison's Weblog
Simon Willison's Weblog
Cisco Talos Blog
Cisco Talos Blog
T
Threatpost
Hugging Face - Blog
Hugging Face - Blog
博客园_首页

博客园 - PKICA

rust性能优化与安全边界 联合体union在rust和C语言中有什么区别 rust并发与异步编程 如何预防rust不良的代码设计总结 rust类型系统与零成本抽象 rust内存模型 告别大显存依赖!用 Rust 新一代深度学习框架 Burn 打造纯 CPU 文本分类推理引擎 rust类型系统标记 编译配置解答 git实用命令 rust底层设计理念值得注意的几个地方总结 rust可变引用作为函数参数的机理详解 Rust内存重解释transmute C与Rust类型映射 Rust FFI 安全抽象范式 rust延迟初始化原语 rust重借用机制与原理 rust参数传递模型 汇编语言语法详解 gdb汇编调试 gdb-pwndbg的安装与使用指南 gdb调试插件gef linux系统readelf命令使用指南 gcore转储进程内存 gdb查看命令 RGB与YUV颜色编码的区别 Rust原子类型 C++ STL求两个集合交集差集 gdb调试集锦 ubuntu24.0.4使用root用户登录 ubuntu24.0.4输入密码后跳回登录界面 AI内存压缩技术TurboQuant及存疑 ubuntu切换到指定内核版本 在没有顶级科技大佬直接背书的情况下deepseek为啥能够异军突起? HuggingFace和deepseek的关系 当前主流AI大模型 Rust写时克隆Cow系列2
C语言thread_local
PKICA · 2026-04-14 · via 博客园 - PKICA

C语言中的 thread_local(在C11标准中为 _Thread_local,通常建议使用 <threads.h> 中的 thread_local 宏)用于声明线程局部存储 (Thread-Local Storage, TLS) 变量。

这种变量在每个线程中都有一个独立的实例,线程之间互不干扰,即使它们共享同一个变量名,在多线程环境下使用它不仅是线程安全的,还避免了互斥锁带来的性能开销。

1. thread_local 的核心特性

  • 线程生存期: 变量在线程启动时生成,在线程结束时销毁。
  • 独立副本: 每个线程存取的是属于自己的副本。
  • 初始化: 不同于普通变量,线程局部变量的值在线程启动时被初始化。
  • 修饰限制: 只能用于全局变量、文件范围的静态变量或函数内部的静态变量。

2. 使用方法 (C11 标准)

C11 标准引入了 _Thread_local 关键字。通常引入 <threads.h> (如果编译器支持) 或在 C23 标准中直接使用 thread_local。 

#include <stdio.h>
#include <threads.h> // C11线程标准库

// 定义一个线程局部变量
thread_local int thread_specific_var = 0;

int main_thread_func(void* arg) {
    thread_specific_var = 10; // 当前线程修改
    printf("Thread %d: var = %d\n", (int)thrd_current(), thread_specific_var);
    return 0;
}

int main() {
    thrd_t t1, t2;
    // 启动两个线程
    thrd_create(&t1, main_thread_func, NULL);
    thrd_create(&t2, main_thread_func, NULL);
    
    // 等待线程结束
    thrd_join(t1, NULL);
    thrd_join(t2, NULL);

    return 0;
}

在上面的示例中,如果 thread_local 没有被定义,两个线程会共享 thread_specific_var 并产生冲突。使用了 thread_local 后,每个线程会打印出各自的 10,互不干扰。

3. 不同标准下的写法

  • C11 / C17: 使用 _Thread_local#include <threads.h> 后的 thread_local
  • C23 : 直接使用 thread_local
  • GCC/Clang 扩展: 使用 __thread 关键字(static __thread int var;),它更早期且实现效率较高。

4. 关键注意事项

  • 静态/全局修饰: 如果在块作用域(函数内部)使用,必须加上 staticextern
  • 性能开销: 线程局部变量的读取通常比全局变量稍慢,且随着线程数量增加,内存占用会增大。
  • 复杂析构函数: 如果线程局部变量需要复杂的析构函数(在C++中更常见),可能会在线程退出时导致意外的释放后使用(use-after-free)问题。
  • 与POSIX pthread_key 区别: thread_local 是一种语言层面的特性,使用起来更简单、更高效,不再需要像 pthread_key_create 那样处理 void* 指针和显式管理内存。

一般,“标准方式”和“编译器扩展方式”区别:

特性_Thread_local (C11)__thread (GNU/Clang)
定义标准 C11 标准关键字 GCC/Clang 编译器扩展
引入方式 包含 <threads.h> 后可用 thread_local 宏 原生支持,无需头文件
约束限制 仅能用于全局或 static 变量 同左
初始化 只能用常量表达式初始化 只能用常量表达式初始化
性能 理论一致 在老版本 GCC 上可能略快

总结

在多线程程序中,如果需要维护线程特有的状态(如错误码 errno、特定线程的日志缓存等),thread_local 是现代C语言(C11及以后)推荐的线程安全实现方式。

参考资料: