可重入(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. 如何选择?

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

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

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


总结

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

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ปรัชญา แค้วคำมูล

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值