重入函数是无需加锁即可安全并发执行的函数,其核心是仅依赖参数和栈变量、不访问全局/静态/堆内存及非可重入库函数;它比线程安全更底层可靠,天然适配中断上下文,避免死锁与阻塞风险。

线程并发中,重入函数是保障程序鲁棒性的底层关键。它不靠加锁兜底,而是从设计源头消除竞态可能——只要函数只依赖参数和栈变量,不碰全局、静态、堆或不可重入库函数,就能在任意时刻被中断、重入、嵌套,结果依然确定可靠。
重入函数的核心判断标准
一个函数是否可重入,看三点:
- 执行中被中断再进入,能否正确恢复并完成原任务
- 多次调用是否各自拥有独立数据空间(仅用栈变量、寄存器参数)
- 是否完全避开共享状态:无全局/静态变量、不返回其地址、不调用 malloc/printf/strtok 等非可重入函数
为什么重入比“加锁线程安全”更底层可靠
线程安全函数常用互斥锁保护全局资源,但锁本身会引入新风险:
- 信号处理函数里调用带锁函数,可能死锁(信号打断时锁未释放)
- 中断上下文不能睡眠,而某些锁实现会阻塞,导致系统挂起
- 可重入函数天然适配中断服务程序(ISR),无需任何同步原语
换句话说,可重入是“无锁安全”,线程安全是“有锁安全”;前者是后者的子集,也更轻量、更确定。
实际编写时必须规避的典型陷阱
这些写法会让函数瞬间失去可重入性:
- 声明 static int counter; 或 static char buf[64];
- 返回 static char result[32]; 的指针
- 调用 strtok()(内部用静态缓冲区)、ctime()(返回静态字符串)
- 在函数内调用 malloc() —— 堆管理器本身依赖全局链表,不可重入
- 使用 printf() 或 fopen() —— 标准I/O维护全局 FILE 结构和缓冲区
简单改造示例:让交换函数真正可重入
下面这个函数看似简洁,实则危险:
static int temp; // 全局临时变量void swap_bad(int* a, int* b) {
temp = *a;
*a = *b;
*b = temp;
}
正确做法是把 temp 移到栈上:
void swap_good(int* a, int* b) {int temp = *a;
*a = *b;
*b = temp;
}
每个调用都拥有自己的 temp,彼此隔离,中断重入也不影响逻辑完整性。











