在一个多任务环境中,一个函数如果可以被多次重复调用,或者被多个任务并发调用,函数在运行过程中可以随时随地被打断,并不影响该函数的运行结果,我们称这样的函数为可重入函数。相反,如果一个函数不能多次并发调用,在执行过程中不能被中断,否则就会影响函数的运行结果,那么这个函数就是不可重入函数。如何判断一个函数是可重入函数,还是不可重入函数呢?规则很简单,一个函数如果满足下列条件中的任何一个,那么这个函数就是不可重入函数。
int a[10]={1,2,3,4,5,6,7,8,9,0};
int b[20]={1,2,3,4,5,6,7,8,9,0,11,12,13,14,9,8};
int sum(int array[],int len)
{
static int sum=0;
for(int i=0;i<len;i++)
{
sum+=i;
}
return sum;
}
void task1(void)
{
sum(a,10);
}
void task2(void)
{
sum(b,20);
}
假设在一个多任务环境中,我们定义了一个sum()函数用来对数组累加求和。sum()函数首先被任务task1调用,在sum()函数运行期间,任务task1被调度器挂起,CPU切换到task2运行,sum()函数被任务task2再次调用。由于sum()函数内定义的有静态变量,当在运行期间
被打断后再次被调用,就有可能影响sum()函数在task1和task2中的运行结果。
在裸机环境下面,我们不需要考虑函数的可重入问题,因为裸机环境下只有一个主程序main()一直在独占CPU运行。但是在多任务环境下,如果该函数可能被多次调用,或者在执行过程中可能会被中断或被任务调度器打断,此时我们就要考虑该函数的可重入问题了。
在多任务系统下,中断可能在任何情况下发生,如果一个函数在执行期间被中断,到它重新恢复到断点处继续执行,函数所依赖的上下文环境没有发生改变,那么这个函数就是可重入的。
在中断发生前后,会保存和恢复上下文,怎么会出现函数所依赖的环境发生改变了呢? 我们知道中断时确实保存一些上下文,但是仅限于返回地址,cpu 寄存器等之类的少量上下文,而函数内部使用的诸如全局或静态变量,buffer 等并不在保护之列,所以如果这些值在函数被中断期间发生了改变,那么当函数回到断点继续执行时,其结果就不可预料了。
在中断处理函数中调用有互斥锁保护的全局变量,如果恰好该变量正在被另一个线程调用,会导致中断处理函数不能及时返回,导致中断丢失等严重问题。