可重入函数
在实时系统的设计中,多个任务经常调用同一个函数。 如果这个函数不幸被设计成不可再输入的函数,
在中,当不同的任务调用此函数时,其他任务可能会修改调用此函数的数据,从而导致意外的结果。
那么,什么是可重入函数呢? 重入是由多个任务调用的过程,无需担心数据是否有误。
不可重入的函数在实时系统设计中被视为不安全的函数。
不能重新输入满足以下条件的许多函数:
(1)函数体内使用了静态的数据结构
)2)在函数中调用malloc (或free )函数;
)3)在函数体内调用了标准I/O函数。
如何编写可重入函数? 在函数中不访问这些全局变量,坚持不使用静态局部变量,只使用默认状态(auto )局部变量。
编写的函数可以重新输入。 如果需要访问全局变量,请记住使用互斥信号量保护全局变量。
或者,在调用此函数之前关闭中断,在调用之后打开中断。
可以在多个任务中调用可重新输入的函数,而不用担心数据被破坏。 可重入函数可以随时中断
,一定时间后可以执行,对应的数据不会丢失。 重新输入函数或仅使用局部变量,
即,保存在CPU寄存器或堆栈中; 或者使用全局变量时,必须保护全局变量。
说法2 :
可重入函数简单来说就是可以中断的函数。 这意味着在此函数运行时可以随时中断他的执行
在调度任务的同时,执行另一段代码而没有错误。 不可重入的函数使用了系统资源,如全局变量区域
因为要中断有向图等,如果他被中断的话就有可能发生问题,所以这样的函数不能在多任务环境下执行。
基本上不能重新输入以下函数
(1)函数体内使用了静态的数据结构
)2)在函数中调用malloc (或free )函数;
)3)在函数体内调用了标准I/O函数。
使不可重入函数可重入的唯一方法是用可重入规则重写他。
其实很简单。 只要遵守几个简单易懂的规则,编写的函数就可以重新输入。
第一,不使用全局变量。 因为其他代码很可能覆盖这些变量的值。
第二,与硬件交互时,请不要忘记执行disinterrupt ()等操作。 这意味着关闭硬件中断。 请记住打开中断以完成对话。 在某些系列中,这将通过“进入/退出核心”或OS_ENTER_KERNAL/OS_EXIT_KERNAL来描述。 //这是临界区的保护
第三,不能调用不可重入的函数。
第四,谨慎使用堆栈。 首先,请在使用OS_ENTER_KERNAL之前使用。
有些规则,都很好理解。 总之,请始终记住保证中断是安全的这句话。
我想很多人都看到过下面的问题
中断是嵌入式系统的重要组成部分,许多编译开发人员提供了中断标准C支持的扩展功能。 代表性的事实是生成了新的关键字__interrupt。 以下代码使用__interrupt关键字定义了中断服务子程序(ISR )。 请评论这个代码的。
_ _ interruptdoublecompute _ area (double radius ) ) { double area=PI * radius * radius; printf((narea=%f ),area ); 返回区域; }
这个函数有太多的错误,我不知道该从何说起了。
1 ) ISR不能返回值。 如果你不知道这个,你就不会被雇佣。
2 ) ISR不能传递参数。 如果你没有看到这一点,你被雇佣的机会就和第一项一样。
3 )在许多处理器/编译器中,浮点一般不能重新输入。 根据处理器/编译器的不同,可能需要堆栈金额的寄存器。
某些处理器/编译器不允许ISR进行浮点运算。 另外,ISR应该短而高效,用ISR进行浮点运算是不明智的。
4 )为了达到第三点,printf ) )经常存在重新输入和性能上的问题。 如果你丢掉第三和第四个,我就不会太为难你了。
不言而喻,如果得到后两点,被雇佣的前景就会越来越光明。
--
如果中断服务程序有返回值,那么该值会返回给谁呢?
系统运行过程中,总会有一些中断源启动相应的中断,与系统连接的中断服务程序进行现场处理,如报警等操作,完成中断。
这意味着中断服务程序链接到一类中断源,这些中断源的出现是随机的,因此中断服务程序没有固定的调用方
也没有固定的返回地址,所以返回值也没有用
r>我的问题是,这里所说的printf()经常有重入的问题,具体是指什么?有人能给解释一下么?
这个概念在嵌入式操作系统中比较重要,由于存在任务的调度,它实时系统,可剥夺型内核中是危险的,如同一个安静的水雷。
可能会被触发,也可能安然无恙。由于它运行结果的不可预期性,会使系统带来隐患。
下面引用一段别人的解释:
这主要在多任务环境中使用,一个可重入的函数简单来说,就是:可以被中断的函数。就是说,你可以在这个函数执行的任何时候中断他的运行,
在OS的调度下去执行另外一段代码而不会出现什么错误。而不可重入的函数由于使用了一些系统资源,
比如全局变量区,中断向量表等等,所以他如果被中断的话,可能出现问题,所以这类函数是不能运行在多任务环境下的。
把一个不可重入函数变成可重入的唯一方法是用可重入规则来重写他。
其实很简单,只要遵守了几条很容易理解的规则,那么写出来的函数就是可重入的。
第一,不要使用全局变量。因为别的代码很可能覆盖这些变量值。
第二,在和硬件发生交互的时候,切记执行类似disinterrupt()之类的操作,就是关闭硬件中断。完成交互记得打开中断,在有些系列上,
这叫做“进入/退出核心”或者用OS_ENTER_KERNAL/OS_EXIT_KERNAL来描述。
第三,不能调用任何不可重入的函数。
第四,谨慎使用堆栈。最好先在使用前先OS_ENTER_KERNAL。
还有一些规则,都是很好理解的,总之,时刻记住一句话:保证中断是安全的!
通俗的来讲吧:由于中断是可能随时发生的,断点位置也是无法预期的。所以必须保证每个函数都具有不被中断发生,
压栈,转向ISR,弹栈后继续执行影响的稳定性。也就是说具有不会被中断影响的能力。既然有这个要求,
你提供和编写的每个函数就不能拿公共的资源或者是变量来使用,因为该函数使用的同时,ISR(中断服务程序)
也可那会去修改或者是获取这个资源,从而有可能使中断返回之后,这部分公用的资源已经面目全非。
满足下列条件的函数多数是不可重入的:
(1)函数体内使用了静态的数据结构;
(2)函数体内调用了malloc()或者free()函数;
(3)函数体内调用了标准I/O函数。
下面举例加以说明。
可重入函数
非可重入函数1
非可重入函数2
如何写出可重入的函数?在函数体内不访问那些全局变量,不使用静态局部变量,坚持只使用局部变量,写出的函数就将是可重入的。
如果必须访问全局变量,记住利用互斥信号量来保护全局变量。
备注:
可重入和线程安全(Thread-Safe)是两个不同的概念:可重入函数一定是线程安全的;线程安全的函数可能是重入的,也可能是不重入的;线程不安全的函数一定是不可重入的。
reentrant函数与是不是多线程无关,如果是reentrant函数,那么要求即使是同一个进程(或线程)同时多次进入该函数时,该函数仍能够正确的运作.
该要求还蕴含着,如果是在多线程环境中,不同的两个线程同时进入该函数时,该函数也能够正确的运作.
thread safe函数是与多线程有关的,它只是要求不同的两个线程同时对该函数的调用在逻辑上是正确的.
本文转自:
http://www.cnblogs.com/AlwaysOnLines/p/3912680.html
https://blog.csdn.net/zyboy2000/article/details/51120771