不可重入函数改造
2026/8/24大约 2 分钟
C语言可重入函数:什么是不可重入,如何改造
可重入函数:
多个执行流同时调用,也不会因为共享状态导致数据互相干扰。
执行流包括:
主程序
中断
任务
线程一、不可重入函数
最典型的问题是使用全局变量或静态变量:
static int count;
int func(void)
{
return ++count;
}多个执行流调用:
Task1 → func()
Task2 → func()
ISR → func()它们共享同一个 count,可能互相影响。
二、改成可重入
把共享状态改成参数和局部变量:
int func(int count)
{
int temp = count + 1;
return temp;
}每次调用都有自己的 temp:
调用1 → temp1
调用2 → temp2
调用3 → temp3互不影响。
核心方法:
全局/静态状态
↓
参数传入
↓
局部变量保存临时状态三、需要共享资源怎么办?
如果确实必须访问共享资源,就要保护它:
共享资源
↓
互斥锁 / 临界区 / 关中断
↓
安全访问例如 RTOS 任务之间共享数据,可以使用:
互斥锁
信号量
临界区
原子操作ISR 中则不能随便使用普通任务锁,要根据具体 RTOS 和执行上下文选择合适的同步方式。
四、常见不可重入来源
全局变量
静态变量
共享缓冲区
非线程安全库函数
依赖共享状态的资源例如:
static char buf[128];
void func(void)
{
// 使用共享 buf
}多个执行流同时进入时,可能覆盖彼此的数据。
五、ISR 为什么特别关注重入?
假设主程序正在执行:
func();执行过程中发生中断:
主程序
↓
func()
↓
中断发生
↓
ISR
↓
再次调用 func()如果 func() 使用共享的静态数据,就可能发生嵌套调用互相破坏状态。
因此:
可能被中断嵌套调用的代码,必须避免依赖未保护的共享状态。
同时,printf()、malloc() 等函数即使存在重入版本问题,也通常不适合直接放在 ISR 中,还因为它们可能执行时间长、依赖共享资源。
六、最终记忆
不可重入
↓
依赖共享状态
↓
多个执行流同时进入
↓
互相干扰
可重入
↓
局部变量 + 参数传递
↓
必要时保护共享资源
↓
多个执行流可以安全调用可重入的核心不是“不能使用全局变量”,而是:函数的正确性不能依赖会被其他执行流同时修改的未保护状态。

