main 函数调用 insert 函数向一个链表 head 中插入节点 node1,插入操作分为两步,刚做完第一步的时候,因为硬件中断使进程切换到内核,再次回用户态之前检查到有信号待处理,于是切换到 sighandler 函数,sighandler 也调用 insert 函数向同一个链表 head 中插入节点 node2,插入操作的两步都做完之后从 sighandler 返回内核态,再次回到用户态就从 main 函数调用的 insert 函数中继续往下执行,先前做第一步之后被打断,现在继续做完第二步。结果是,main 函数和 sighandler 先后向链表中插入两个节点,而最后只有一个节点真正插入链表中了。

一般而言,我们认为 main执行流 和 信号捕捉执行流 是两个执行流!但是要注意的是其实它们本质上还是一个执行流,只不过从逻辑上来说,它们对彼此会造成影响,所以我们认为其是两个执行流!
- 如果在
main中和在handler中,该函数被重复进入,并且出问题了,那么该函数我们叫做不可重入函数。 - 如果在
main中和在handler中,该函数被重复进入,并且没有发生问题,那么该函数我们叫做可重入函数。
那么问题来了,不可重入函数和重入函数是我们需要去解决的问题吗❓❓❓
不是的,我们目前大部分使用的接口都是不可重入函数,特别是 STL 中的容器有各种涉及插入、删除等操作,它们都是不可重入函数,这是一种特性,是中性词,而不是问题! 所以它不需要我们去解决,我们只需要理解它们的特性即可!
如果一个函数符合以下条件之一则是不可重入的:
- 调用了
malloc或free,因为malloc也是用全局链表来管理堆的。 - 调用了标准
I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构。