何为函数的重入?
函数的重入是指对函数进行并发访问,比如函数F正在运行,由于中断或者多任务调度,函数F会被打断,失去对CPU控制权,而中断服务程序ISR或者其他任务再一次调用函数F,这就造成了函数F的重入。
引起函数重入的情况
总的来说,引起函数发生重入的情况有3种:
- 中断
- 多任务调度
- 递归函数
函数可重入的条件
并非所有函数都可以发生重入并且保证安全地执行,如malloc函数,如果发生了重入,很可能会导致很严重的后果,甚至系统崩溃。
被重入后依然能正确执行的函数称作可重入函数,反之称为不可重入函数。实际上没有对临界资源采取互斥保护就使用临界资源的函数都是不可重入的,这里的临界资源包含全局变量、UART设备、打印机设备等。
比如下面这个例子:
char str[10];
int func(char *p)
{
int i = 0;
char *p1 = p;
for(i=0; i<10; i++)
{
str[i] = *p1++;
}
return 0;
}
当前函数对str赋值的循环进行到一半时,发生了中断,并且在中断中重新调用该函数进行赋值操作,那么这就会造成第一次对str赋值的那一半数据被覆盖掉,中断返回后,继续下面的赋值,最终的结果是str中前一半数据时中断程序给的,后一半数据是中断返回后给的。很显然这样的赋值数据是不对的。
如何保护不可重入函数?
函数不可重入的原因是函数中使用了临界资源,保护不可重入如函数其实就是要保证函数对临界资源进行访问时不会出现代码执行逻辑错误。这时就要用到互斥的概念了。
所谓互斥,就是指同一临界资源不能被并发访问,简单来说就是函数A在使用资源S时,函数B不能同时访问,必须要在函数A将资源S的访问权交出去并且函数B获得了资源S的访问权后才能进行使用。
保证互斥的方法有:
- 关中断
- 禁止任务调度
- 信号量
给自己的建议
在今后编程时,需要清楚知道哪些函数是安全可重入的。