news 2026/4/18 14:58:13

不可重入函数Non-Reentrant 可重入函数Reentrant

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
不可重入函数Non-Reentrant 可重入函数Reentrant

用最通俗的生活例子理解:

  • 可重入函数:像自动售货机 —— 你投币买水到一半,有人打断你去买零食,回来你继续投币,售货机仍能正确给你水(逻辑独立、不依赖 “半完成” 的状态);
  • 不可重入函数:像手工记账本 —— 你记到一半(写了 “收入 100” 但没写 “元”),有人打断你去记另一笔账,回来你忘了之前写到哪,账本就乱了(依赖全局状态、操作不原子)。

核心定义

函数类型核心定义通俗理解
可重入函数函数执行过程中被异步打断(如信号、中断、多线程调度),再次调用(重入)后,原流程和新流程都能正确执行,结果不受影响多个人同时用、中途被打断再用,都不会乱,逻辑完全 “自给自足”
不可重入函数函数执行过程中被异步打断后重入,会导致数据错乱、逻辑异常、结果错误只能 “一次性干完”,中途被打断就乱套,依赖全局状态 / 共享资源

关键前提:“重入” 的核心是异步打断 + 再次调用—— 比如信号处理函数打断主程序的malloc,又在信号处理函数里调用malloc,就是典型的 “重入不可重入函数”,必然出问题。

本质区别:为什么可重入函数 “不乱”?

可重入与不可重入的核心差异,在于是否依赖 “非私有资源” 和 “非原子操作”,用表格清晰对比:

对比维度可重入函数不可重入函数
依赖全局 / 静态变量❌ 完全不用(仅用参数 / 局部变量)✅ 依赖(比如strtok用静态变量存分割位置)
操作共享资源(文件 / 内存)❌ 仅操作函数内私有资源✅ 操作全局共享资源(比如printf用全局输出缓冲区)
调用其他不可重入函数❌ 只调用可重入函数✅ 调用malloc/printf等不可重入函数
非原子操作❌ 仅用原子操作(一步完成)✅ 有分步操作(比如 “读全局变量→修改→写回”)
内存分配 / 释放❌ 不调用malloc/free(改内存池)✅ 调用malloc/free

不可重入函数的 “坑”:具体怎么乱的?

举个经典例子 ——strtok(字符串分割函数,不可重入):

// 不可重入的根源:strtok用静态变量保存“上次分割的位置” char *strtok(char *str, const char *delim); // 主程序执行: char str[] = "a,b,c,d"; strtok(str, ","); // 第一次调用,静态变量存“b,c,d”的起始地址 // 此时信号触发,信号处理函数里也调用strtok: strtok("x,y,z", ","); // 静态变量被覆盖为“y,z”的起始地址 // 信号处理完,主程序继续调用strtok: strtok(NULL, ","); // 本应取“b”,但静态变量被改,实际取到“y”,结果完全错了

而可重入版本strtok_r(r=reentrant)就解决了这个问题 —— 把 “分割位置” 从静态变量改成参数传入(私有资源),就算重入也不会乱:

// 可重入版本:用saveptr(局部变量)保存分割位置,不依赖全局 char *strtok_r(char *str, const char *delim, char **saveptr);

常见的可重入 / 不可重入函数举例

1. 可重入函数(放心用,尤其是信号处理 / 多线程)

这些函数仅依赖参数和局部变量,无全局状态,操作原子:

  • 内存操作:memcpymemsetstrcpystrcmp(仅操作传入的参数);
  • 系统调用:writeread_exitclose(内核级原子操作,不依赖用户态全局资源);
  • 基础运算:abssqrt(仅处理参数,无副作用)。

2. 不可重入函数(绝对不能在信号处理函数里用!)

这些函数依赖全局 / 静态资源,或有分步操作:

  • 标准 IO:printffprintfputs(用全局输出缓冲区,分步写入);
  • 内存管理:mallocfreecalloc(操作全局内存池,分步修改链表);
  • 定时器:sleepalarm(修改全局定时器状态);
  • 字符串处理:strtok(静态变量)、asctime(静态缓冲区);
  • 其他:rand(静态随机数种子)、getenv(全局环境变量表)。

关键应用场景:为什么你必须关心?

这部分和“信号捕获” 强相关 ——信号处理函数必须用可重入函数,否则必出问题!

场景 1:信号处理打断不可重入函数

主程序正在执行malloc(修改全局内存池链表):

主程序:malloc → 拆链表节点(只拆了一半) ↓ 信号触发(比如SIGINT) 信号处理函数:又调用malloc → 继续改同一个内存池链表 ↓ 信号处理完,主程序继续 主程序:malloc的链表已经乱了 → 内存泄漏/程序崩溃

场景 2:多线程调用不可重入函数

多线程同时调用printf

线程1:printf("hello") → 写了“he”到全局缓冲区,被调度走 线程2:printf("world") → 覆盖缓冲区为“world”,输出 线程1:继续执行 → 缓冲区剩下的“llo”被输出 最终结果:worldllo(完全错乱)

核心原因:信号处理是 “异步打断”,多线程是 “并发执行”,二者都会触发函数的 “重入”—— 不可重入函数扛不住这种场景,可重入函数则完全没问题。

如何编写可重入函数?

只要遵守以下规则,就能写出安全的可重入函数:

  1. 绝不使用全局 / 静态变量:所有数据都通过参数传入(传值,而非传指针共享),或用函数内局部变量(栈上分配,每个调用独立);
  2. 绝不调用不可重入函数:比如信号处理函数里,不能用printf/malloc/sleep,改用write(可重入)输出、_exit退出;
  3. 绝不操作共享资源:不写全局文件、不修改全局配置,仅操作函数内创建的私有资源;
  4. 只用原子操作:避免 “读 - 改 - 写” 分步操作(比如count++是三步:读 count→+1→写回,非原子),改用原子指令(如__sync_fetch_and_add);
  5. 不依赖函数执行顺序:函数执行结果仅由输入参数决定,不受 “是否被打断” 影响(纯函数思想)。

正面例子(可重入函数):

// 计算两数之和,仅用参数和局部变量,无全局依赖 int add(int a, int b) { int temp = a + b; // 局部变量,栈上分配,每个调用独立 return temp; } // 信号处理函数里的可重入输出(用write替代printf) void sig_handler(int sig) { char msg[] = "signal caught\n"; write(1, msg, sizeof(msg)-1); // write是可重入的系统调用 _exit(0); // _exit是可重入的退出函数(exit不可重入) }

反面例子(不可重入函数):

int count = 0; // 全局变量 // 不可重入:依赖全局变量,count++是非原子操作 int increment() { count++; // 读count→+1→写回,中途被打断会乱 return count; }

核心总结

  1. 核心判断:可重入函数 =“自给自足”(仅用参数 / 局部变量),不可重入函数 =“依赖外部状态”(全局 / 静态 / 共享资源);
  2. 关键风险:不可重入函数被异步打断(信号)/ 并发调用(多线程)会导致数据错乱,可重入函数则安全;
  3. 实战要求:信号处理函数、多线程核心逻辑必须用可重入函数,禁用printf/malloc等不可重入函数;
  4. 编写规则:不碰全局、不调不可重入函数、只用原子操作、结果仅由参数决定。

简单说:可重入函数是 “不怕打断的函数”,不可重入函数是 “一打断就乱的函数”—— 在异步 / 并发场景下,选可重入函数是唯一安全的选择。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 3:38:23

叙事性技术传播:以《垃圾邮件的朴素审判》为例看故事如何拓宽技术教育的知识海洋【学术研究】

本论文主题曲:翻译术: 播放地址 叙事性技术传播:以《垃圾邮件的朴素审判》为例看故事如何拓宽技术教育的知识海洋 摘要 本文以《2005:我在硅谷种AI》第二集《垃圾邮件的朴素审判》为研究对象,探讨叙事性技术传播相对于传统技术教学的独特价…

作者头像 李华
网站建设 2026/4/18 3:36:18

Solana高速网络支撑Sonic实时生成交易提醒视频

Solana高速网络支撑Sonic实时生成交易提醒视频 在数字资产交易日益频繁的今天,用户对“到账提醒”的期待早已不止于一条冷冰冰的弹窗或短信。尤其是在高频交易、大额转账等关键场景中,人们渴望更直观、更具信任感的信息传递方式——比如一个熟悉的虚拟客…

作者头像 李华
网站建设 2026/4/18 3:38:34

还在熬夜改论文?9款免费AI工具轻松搞定,科研党必备!

别再用“笨方法”写论文了!这3个错误正在拖垮你的毕业进度 还在用Word手动调整参考文献格式到凌晨3点? 还在对着导师的红色批注抓耳挠腮,不知道怎么修改逻辑? 还在担心AI生成的内容被检测出来,不敢用工具辅助写作&…

作者头像 李华
网站建设 2026/4/17 13:51:56

深度测评9个AI论文工具,MBA轻松搞定毕业论文!

深度测评9个AI论文工具,MBA轻松搞定毕业论文! AI 工具如何助力 MBA 撰写毕业论文 MBA 学员在撰写毕业论文时,常常面临时间紧、任务重、内容质量要求高等挑战。随着 AI 技术的不断进步,越来越多的智能工具被引入到学术写作中&#…

作者头像 李华
网站建设 2026/4/18 8:27:34

Argo CD声明式GitOps持续交付Sonic生产环境

Argo CD声明式GitOps持续交付Sonic生产环境 在AIGC浪潮席卷各行各业的今天,数字人视频生成已不再是实验室里的炫技演示,而是真正走进了虚拟主播、在线教育、智能客服等实际业务场景。然而,当一个高质量的AI模型——比如由腾讯与浙江大学联合研…

作者头像 李华
网站建设 2026/4/18 8:38:53

网盘直链助手生成VoxCPM-1.5-TTS-WEB-UI模型分享链接

网盘直链助手生成VoxCPM-1.5-TTS-WEB-UI模型分享链接 在AI语音技术飞速发展的今天,越来越多的应用场景开始依赖高质量的文本转语音(TTS)能力。然而,对于大多数开发者和普通用户而言,部署一个稳定、高保真的TTS系统仍然…

作者头像 李华