若一个程序或子程序可以“安全的被并行执行(Parallel computing)”,则称其为可重入(reentrant或re-entrant)的。即当该子程序正在运行时,可以再次进入并执行它(并行执行时,个别的执行结果,都符合设计时的预期)。
简单上来说,就是:可以被中断的函数。就是说,你可以在这个函数执行的任何时候中断他的运行,在任务调度下执行下段代码而不会出现什么错误。而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等等,所以他如果被中断的话,可能出现问题,所以这类函数是不能运行在多任务环境下的。
例子
在以下的C语言代码中,函数f和函数g都不是可重入的。
int g_var = 1; /* 全局变量 */ int f() { g_var = g_var + 2; return g_var; } int g() { return f() + 2; }
以上代码中,f使用了全局变量 g_var,所以,如果两个线程同时执行它并访问g_var,则返回的结果取决于执行的时间。因此,f不可重入。而g调用了f,所以它也不可重入。
稍作修改后,两个函数都是可重入的:
int f(int i) { return i + 2; } int g(int i) { return f(i) + 2; } 有带以下特征的,基本上都是不可重入的 1:函数体内使用了静态的数据结构; 2:函数体内调用了malloc()或者free()函数; 3:函数体内调用了标准I/O函数。 把一个不可重入函数变成可重入的唯一方法是用可重入规则来重写他。 只要遵守了几条规则,那么写出来的函数就是可重入的。 1:尽量不要使用全局变量,因为其它代码很可能覆盖这些变量值。如果必须访问全局变量,记住利用互斥信号量来保护全局变量,或者调用该函数前关中断,调用后再开中断。 2:在和硬件发生交互的时候,切记执行类似disinterrupt()之类的操作,就是关闭硬件中断。完成交互记得打开中断,在有些系列上,这叫做“进入/退出核心”或者用OS_ENTER_KERNAL/OS_EXIT_KERNAL来描述。//这是临界区保护 3:不能调用任何不可重入的函数。 4:谨慎使用堆栈。最好先在使用前先OS_ENTER_KERNAL。 5:还有一些规则,都是很好理解的,总之,时刻记住一句话:保证中断是安全的!