当前位置: 首页 > news >正文

可重入(Reentrant) vs 线程安全(Thread-Safe)

可重入(Reentrant) vs 线程安全(Thread-Safe)的区别

在并发编程中,可重入线程安全是两个容易混淆但本质不同的概念。它们的核心区别在于 作用域 和 并发环境下的行为


1. 可重入(Reentrant)

定义

一个函数或代码块如果在 同一线程 被多次调用(如递归、中断、信号处理)时能正确执行,就称为 可重入

关键特性

✅ 同一线程安全:可以被同一线程多次进入而不出错。
❌ 不保证多线程安全:如果多个线程同时调用,可能仍然存在竞争条件。

可重入的条件

  1. 不依赖全局/静态变量(使用局部变量或参数)。

  2. 不调用非可重入函数(如 mallocprintf 在某些实现中不可重入)。

  3. 不修改共享数据(除非通过锁或原子操作)。

示例

// 可重入函数(仅依赖参数和局部变量)
int add(int a, int b) {return a + b;  // 无共享状态,可重入
}// 不可重入函数(依赖全局变量)
int counter = 0;
void increment() {counter++;  // 修改全局变量,不可重入
}

2. 线程安全(Thread-Safe)

定义

一个函数或代码块在 多个线程并发调用 时仍能正确执行,称为 线程安全

关键特性

✅ 多线程安全:多个线程同时调用不会导致数据竞争或逻辑错误。
❌ 不一定是可重入的:线程安全可能通过全局锁实现,但锁的递归调用可能导致死锁(不可重入)。

线程安全的实现方式

  1. 无共享状态(如只读数据或线程局部存储)。

  2. 原子操作(如 std::atomic)。

  3. 同步机制(如互斥锁、信号量)。

示例

#include <mutex>
std::mutex mtx;
int shared_counter = 0;// 线程安全函数(通过互斥锁保护)
void safe_increment() {mtx.lock();shared_counter++;  // 受锁保护,线程安全mtx.unlock();
}// 线程安全但不可重入(同一线程重复加锁会死锁)
void unsafe_reentrant() {mtx.lock();// 如果同一线程再次调用,会死锁!mtx.unlock();
}

3. 关键区别对比

特性可重入(Reentrant)线程安全(Thread-Safe)
作用域同一线程内多次调用多线程并发调用
依赖数据避免全局/静态变量可安全访问共享数据
实现方式无共享状态或递归锁锁、原子操作、无状态设计
是否隐含对方❌ 不保证线程安全❌ 不保证可重入(可能死锁)
典型场景递归函数、信号处理多线程共享资源访问

4. 常见关系

(1) 可重入 + 线程安全

  • 无状态函数(如纯函数)既是可重入的,也是线程安全的。

    int add(int a, int b) { return a + b; }  // 可重入 & 线程安全

(2) 可重入但非线程安全

  • 依赖线程局部存储(TLS)的函数是可重入的,但多线程访问 TLS 可能不安全。

    thread_local int local_counter = 0;
    void increment_local() { local_counter++; }  // 可重入,但非线程安全(如果跨线程访问 TLS)

(3) 线程安全但不可重入

  • 使用非递归锁的函数是线程安全的,但同一线程重复加锁会死锁。

    std::mutex mtx;
    void safe_but_not_reentrant() {mtx.lock();// 同一线程再次调用会死锁!mtx.unlock();
    }

(4) 不可重入且非线程安全

  • 直接操作全局变量的函数既不可重入,也不线程安全。

    int global = 0;
    void unsafe_func() { global++; }  // 非可重入,非线程安全

5. 如何选择?

  • 需要递归/信号处理 → 确保 可重入(避免全局数据,或用递归锁)。

  • 需要多线程并发 → 确保 线程安全(加锁、原子操作或无状态设计)。

  • 既要可重入又要线程安全 → 使用 无状态设计 或 递归锁+原子操作


总结

  • 可重入:关注 同一线程 的重复调用安全性。

  • 线程安全:关注 多线程 并发调用的正确性。

  • 两者无必然联系,但可通过合理设计同时满足(如无状态函数)。

关键口诀
🔹 “可重入管自己,线程安全管别人。”
🔹 “无状态通吃,有共享需锁。”

相关文章:

  • AI Agent开发第71课-一个完善的可落地企业AI Agent全架构
  • 视觉-语言导航:综述与类别
  • idea2024 不知道安装了什么插件,界面都是中文的了,不习惯,怎么修改各个选项改回英文
  • 网络安全-等级保护(等保) 2-7 GB/T 25058—2019 《信息安全技术 网络安全等级保护实施指南》-2019-08-30发布【现行】
  • upload-labs靶场通关详解:第11关
  • Java后端面试八股文大全(2025最新版)
  • 【八股战神篇】Java多线程高频面试题(JUC)
  • MongoDB及spring集成
  • SGLang和vllm比有什么优势?
  • 本案例介绍ABB电机保护单元如何走profibus总线通讯
  • stm32week16
  • MIME类型详解及应用案例
  • 【QT】一个界面中嵌入其它界面(二)
  • 数据库存储空间告急?磁盘清理与归档策略全解析
  • docker介绍与常用命令汇总
  • 火山 RTC 引擎9 ----集成 appkey
  • BM25(Best Matching 25)介绍与使用
  • 基于Zynq SDK的LWIP UDP组播开发实战指南
  • 对抗性机器学习:AI模型安全防护新挑战
  • 在linux平台下利用mingw64编译windows程序
  • 住建部:截至去年底常住人口城镇化率达到67%
  • C919上海虹桥-深圳航线开通,东航今年计划再接收10架C919
  • “南昌航空一号”成功发射,赣江鄱阳湖有了专属卫星守护
  • 国家防汛抗旱总指挥部对15个重点省份开展汛前实地督导检查
  • 病重老人取钱在银行门口去世,家属:已协商一致
  • 独家 |《苏州河》上海上演,编剧海飞:上海的风能吹透我