C之可重入函数 && 不可重入函数

嵌入式实时系统设计中,经常碰到多个任务调用同一个函数的情况。如果此函数当初不幸被设计成不可重入函数的话,那么不同任务调用该函数时可能修改其他任务调用该函数的数据,从而导致不可预料的后果。

那么什么是可重入函数呢?所谓可重入是指一个可以被多个任务调用的过程,任务在调用时不必担心数据是否会出错。不可重入函数在实时系统设计中被视为不安全函数。

满足下列条件的函数多数是不可重入的:

(1)函数体内使用了静态的数据结构;

(2)函数体内调用了malloc()或者free()函数;

(3)函数体内调用了标准I/O函数;

如何写出可重入的函数?在函数体内不访问那些全局变量,不使用静态局部变量,坚持只使用缺省态(auto)局部变量,写出的函数就将是可重入的。如果必须访问全局变量,记住利用互斥信号来保护全局变量,或者调用该函数前关中断,调用后再开中断。

可重入函数可以被一个以上的任务调用,而不必担心数据被破坏。可重入函数任何时候都可以被中断,一段时间以后又可以运行,而相应的数据不会丢失。可重入函数或者只使用局部变量,即保存在CPU寄存器中或堆栈中;或者使用全局变量,则要对全局变量予以保护。

写可重入函数应遵守的规则:

Rule 1、不要使用全局变量。因为别的代码很可能覆盖这些变量值。

Rule2、在和硬件交互时,谨记执行类似disinterrupt()之类的操作,即为关闭硬件中断。交互结束切记打开中断,在某些系列上,这叫做“进入/退出核心”或者用OS_ENTER_KERNAL/OS_EXIT_KERNAL来描述。/*这是临界区保护*/

Rule3、不能调用任何不可重入的函数。

Rule4、谨慎使用堆栈。最好先在使用前先OS_ENTER_KERNAL。

总之,在灵魂深处时刻呼唤:保证中断是安全的!!!!!

 

中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展——让标准C支持中断。具体代表事实即产生了一个新的关键字__interrupt关键字去定义了一个中断服务子程序(ISR),请评论以下代码段:

__interrupt double compute_area (double radius)

{

double area = PI  *  radius * radius;

printf(“\nArea = %f”, area);

return area;

}

该函数就是为面试而生的啊,错误很多:

1)ISR不能返回一个值。如果你不懂这个,洗洗睡吧,好有精神找下一家。

2)ISR不能传递参数。如果你没有看到这一点,结果参考第一点。

3)在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需            要让额外的寄存器入栈,有些处理器/编译器就不允许在ISR中做浮点运算。此          外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智,不可取的。

4)与第三点一脉相承,printf()经常有重入和性能上的问题。

/**********************************************************************************************//在系统运行过程中,一定是某种中断源发出了相应的中断,系统上挂接的中断服

//务程序进行现场的处理,例如告警等操作,然后清中断。即中断服务程序连接在

//某一类中断源上,而这些中断源的产生是随机的,所以中断服务程序并没有一个

//固定的调用者,也没有固定的返回地址,故返回值也没有用。以下举例说明可重

//入函数 && 不可重入函数。

/**********************************************************************************************

//可重入函数

void strcpy(char* lpszDest, char* lpszSrc)

{

while(*lpszDest++ = *lpszSrc++);

*dest = 0;

}

//不可重入函数1

char cTemp;                                //全局变量

void SwapChar1(char* lpcX, char* lpcY)

{

cTemp = *lpcX;

*lpcX = *lpcY;

*lpcY = cTemp;      //访问了全局变量,在分享内存的多个线程中可能造成问题

}

//非可重入函数2

void SwapChar2(char* lpcX, char*lpcY)

{

static char cTemp;             //静态局部变量

cTemp = *lpcX;

*lpcX= *lpcY;

*lpcY = cTemp;      //使用静态局部变量,在分享内存多个线程中可能造成问题

}

最后问一遍如何写出可重入的函数?在函数体内不访问那些全局变量,不使用静态局部变量,坚持只使用局部变量,写出的函数就将是可重入的。如果必须访问全局变量,记住利用互斥信号量来保护全局变量。

发表评论

电子邮件地址不会被公开。 必填项已用*标注