可重入函数:
1.定义:
可重入函数:可以被两个或多个执行流进入的函数,并且产生的结果是正确的,可以在函数执行的任何时候中断它,它主要用于多任务环境。
不可重入函数:因为重入而导致错误的函数称为不可重入函数。
2.不可重入的条件(只要满足一下其中任意一个条件就不可重入):
(1)函数内使用了静态数据结构;
(2)函数内调用了malloc(),free();
(3)函数内部调用了标准输入,标准输出;
3.编写可重入函数的规则:
(1)尽量使用局部变量,不要使用全局变量,如果必须访问全局变量时,要利用互斥信号量来保护全局变量;
(2)和硬件发生交互时,要关闭硬件中断;
(3)不调用任何不可重入的函数;
(4)使用堆栈时要谨慎;
用例子来证明一下:
main函数调用insert函数向一个链表head中插入节点node1,插入操作分为两步,刚做完第一步的时候,因为硬件中断使进程切换到内核,再次回用户态之前检查到有信号待处理,于是切换到sighandler函数,sighandler也调用insert函数向同一个链表head中插入节点node2,插入操作的两步都做完之后从sighandler返回内核态,再次回到用户态就从main函数调用的insert函数中继续往下执行,先前做第一步之后被打断,现在继续做完第二步。结果是,main函数和sighandler先后 向链表中插入两个节点,而最后只有一个节点真正插入链表中了。
insert函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函 数,这称为重入,insert函数访问一个全局链表,有可能因为重入而造成错乱,像这样的函数称为不可重入函数。
线程安全
1.定义:
线程安全即多线程访问时,采用加锁机制,在线程访问类中的数据时,进行了数据保护;
2.如果一个函数能安全的同时被多个线程调用,并得到正确的结果,那么这个函数就是线程安全的;
3.所有导致结果不正确的因素,都是不安全的调用;
4.线程的安全问题一般是由全局变量和静态变量引起的;
5.线程安全不要求调用的函数结果具有可再现性;
6.如何避免线程不安全问题:
若每个线程对全局变量、静态变量只有读操作,那么这个全局变量是线程安全的,如果同时对它执行写操作,必须要考虑线程同步,负责影响线程安全
7.我们将线程不安全函数分为四种类型(有交叉):
①不保护共享变量的函数
②保持跨越多个调用的状态函数
③返回指向静态变量指针的函数
④调用线程不安全函数的函数
可重入函数与线程安全的区别联系
由可重入函数和线程安全的特点可以知道:
1.可重入函数一定是线程安全的,但线程安全不一定是可重入的;
2.可重入函数和线程安全都与全局变量有关;
3.当对临界资源的访问加锁保护时,函数时线程安全的,但对可重入函数加锁后没有释放锁时,会造成死锁,变为不可重入;
4.可重入函数强调不同执行流对数据的操作互不影响,而且结果相同,但是线程安全允许在调用该函数时,出现互相影响的情况,只要使用互斥锁保证安全性即可;
5.对于一个不可重入函数,可以通过互斥锁让它安全的被多个线程同时调用,那么这个不可重入函数转换成为了线程安全;
下面呢我用一张图表示他们间明显的关系: