C语⾔可重⼊函数和不可重⼊函数
可重⼊函数和不可重⼊函数的概念
  在函数中如果我们使⽤静态变量了,导致产⽣中断调⽤别的函数的过程中可能还会调⽤这个函数,于是原来的静态变量被在这⾥改变了,然后返回主体函数,⽤着的那个静态变量就被改变了,导致错误。这类函数我们称为不可重⼊函数。
  如果是在函数体内动态申请内存的话,即便新的线程调⽤这个函数也没事,因为新的线程使⽤的是新的函数的新申请的动态内存(静态变量只有⼀份,所以多线程对于函数体内的静态变量改变会有⽆法修复的结果),所以这类函数就是可重⼊函数。
在实时系统的设计中,经常会出现多个任务调⽤同⼀个函数的情况。如果这个函数不幸被设计成为不可重⼊的函数的话,那么不同任务调⽤这个函数时
可能修改其他任务调⽤这个函数的数据,从⽽导致不可预料的后果。那么什么是可重⼊函数呢?所谓可重⼊是指⼀个可以被多个任务调⽤的过程,任务在
调⽤时不必担⼼数据是否会出错。不可重⼊函数在实时系统设计中被视为不安全函数。
满⾜下列条件的函数多数是不可重⼊的:
(1)函数体内使⽤了静态的数据结构;
(2)函数体内调⽤了malloc()或者free()函数;
(3)函数体内调⽤了标准I/O函数。
如何写出可重⼊的函数?在函数体内不访问那些全局变量,不使⽤静态局部变量,坚持只使⽤缺省态(auto)局部变量,写出的函数就将是可重⼊的。如果
必须访问全局变量,记住利⽤互斥信号量来保护全局变量。或者调⽤该函数前关中断,调⽤后再开中断。
c语言编译器怎么用不了
可重⼊函数可以被⼀个以上的任务调⽤,⽽不必担⼼数据被破坏。可重⼊函数任何时候都可以被中断,⼀段时间以后⼜可以运⾏,⽽相应的数据不会丢失。
可重⼊函数或者只使⽤局部变量,即保存在CPU寄存器中或堆栈中;或者使⽤全局变量,则要对全局变量予以保护。
说法2:
⼀个可重⼊的函数简单来说,就是:可以被中断的函数。就是说,你可以在这个函数执⾏的任何时候中断他的运⾏,在任务调度下去执⾏另外⼀段代码⽽
不会出现什么错误。⽽不可重⼊的函数由于使⽤了⼀些系统资源,⽐如全局变量区,中断向量表等等,所以他如果被中断的话,可能出现问题,所以这类函
数是不能运⾏在多任务环境下的。
基本上下⾯的函数是不可重⼊的
(1)函数体内使⽤了静态的数据结构;
(2)函数体内调⽤了malloc()或者free()函数;
(3)函数体内调⽤了标准I/O函数。
把⼀个不可重⼊函数变成可重⼊的唯⼀⽅法是⽤可重⼊规则来重写他。
其实很简单,只要遵守了⼏条很容易理解的规则,那么写出来的函数就是可重⼊的。
第⼀,不要使⽤全局变量。因为别的代码很可能覆盖这些变量值。
第⼆,在和硬件发⽣交互的时候,切记执⾏类似disinterrupt()之类的操作,就是关闭硬件中断。完成交互记得打开中断,在有些系列上,这叫做“进⼊/退出核
⼼”或者⽤OS_ENTER_KERNAL/OS_EXIT_KERNAL来描述。//这是临界区保护
第三,不能调⽤任何不可重⼊的函数。
第四,谨慎使⽤堆栈。最好先在使⽤前先OS_ENTER_KERNAL。
还有⼀些规则,都是很好理解的,总之,时刻记住⼀句话:保证中断是安全的!
相信很多⼈都看过下⾯这个⾯试题
中断是嵌⼊式系统中重要的组成部分,这导致了很多编译开发商提供⼀种扩展—让标准C⽀持中断。具代表事实是,产⽣了⼀个新的关键字 __interrupt。下
⾯的代码就使⽤了__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()经常有重⼊和性能上的问题。如果你丢掉了第三和第四点,我不会太为难你的。不⽤说,如果你能得到后两点,那么你的被雇⽤前景越来越光明了。
-
->
如果说中断服务程序有返回值,那么它的值返回给谁呢?
在系统的运⾏过程中,⼀定是某种中断源出发了相应的中断,系统上挂接的中断服务程序进⾏现场的处理,例如告警等操作,然后清中断。
也就是说中断服务程序链接在某⼀类中断源上,⽽这些中断源的产⽣是随机的,所以,中断服务程序并没有⼀个固定的调⽤者,也没有固定的返回地址,所以返回值也没有⽤
我的问题是,这⾥所说的printf()经常有重⼊的问题,具体是指什么?有⼈能给解释⼀下么这个概念在嵌⼊式操作系统中⽐较重要,由于存在任务的调度,它实时系统,可剥夺型内核中是危险的,如同⼀个安静的⽔雷。可能会被触发,也可能安然⽆恙。由于它运⾏结果的不可预期性,会使系统带来隐患。
下⾯引⽤⼀段别⼈的解释:
这主要在多任务环境中使⽤,⼀个可重⼊的函数简单来说,就是:可以被中断的函数。就是说,你可以在这个函数执⾏的任何时候中断他的运⾏,在OS的调度下去执⾏另外⼀段代码⽽不会出现什么错误。⽽不可重⼊的函数由于使⽤了⼀些系统资源,⽐如全局变量区,中断向量表等等,所以他如果被中断的话,可能出现问题,所以这类函数是不能运⾏在多任务环境下的。
把⼀个不可重⼊函数变成可重⼊的唯⼀⽅法是⽤可重⼊规则来重写他。
其实很简单,只要遵守了⼏条很容易理解的规则,那么写出来的函数就是可重⼊的。
第⼀,不要使⽤全局变量。因为别的代码很可能覆盖这些变量值。
第⼆,在和硬件发⽣交互的时候,切记执⾏类似disinterrupt()之类的操作,就是关闭硬件中断。完成交互记得打开中断,在有些系列上,这叫做“进⼊/退出核⼼”或者⽤OS_ENTER_KERNAL/OS_EXIT_KERNAL来描述。
第三,不能调⽤任何不可重⼊的函数。
第四,谨慎使⽤堆栈。最好先在使⽤前先OS_ENTER_KERNAL。
还有⼀些规则,都是很好理解的,总之,时刻记住⼀句话:保证中断是安全的!
通俗的来讲吧:由于中断是可能随时发⽣的,断点位置也是⽆法预期的。所以必须保证每个函数都具有不被中断发⽣,压栈,转向ISR,弹栈后继续执⾏影响的稳定性。也就是说具有不会被中断影响的能⼒。既然有这个要求,你提供和编写的每个函数就不能拿公共的资源或者是变量来使⽤,因为该函数使⽤的同时,ISR(中断服务程序)也可那会去修改或者是获取这个资源,从⽽有可能使中断返回之后,这部分公⽤的资源已经⾯⽬全⾮。
满⾜下列条件的函数多数是不可重⼊的:
(1)函数体内使⽤了静态的数据结构;
(2)函数体内调⽤了malloc()或者free()函数;
(3)函数体内调⽤了标准I/O函数。
下⾯举例加以说明:
可重⼊函数:
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;  // 使⽤了静态局部变量,在分享内存的多个线程中可能造成问题
}
如何写出可重⼊的函数?在函数体内不访问那些全局变量,不使⽤静态局部变量,坚持只使⽤局部变量,写出的函数就将是可重⼊的。如果必须访问全局变量,记住利⽤互斥信号量来保护全局变量。 

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。