可重入函数


可重入函数:


在 实时系统的设计中,经常会出现多个任务调用同一个函数的情况。如果这个函数不幸被设计成为不可重入的函数的话,那么不同任务调用这个函数时可能修改其他任 务调用这个函数的数据,从而导致不可预料的后果。那么什么是可重入函数呢?所谓可重入是指一个可以被多个任务调用的过程,任务在调用时不必担心数据是否会 出错。不可重入函数在实时系统设计中被视为不安全函数。


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


(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。

还有一些规则,都是很好理解的,总之,时刻记住一句话:保证中断是安全的


------------------------------------------------------------------------------------------------------------------------------------------------------------

1、可重入函数

    可重入函数指的是可以被中断的函数。也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误;而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下的。I/O代码通常不是可重入的,因为它们依赖于像磁盘这样共享的,单独的资源。

2、可重入的条件

    不含有静态(全局)非常量数据

    不返回静态(全局)非常量数据的地址

    只处理由调用者提供的数据

    不能依赖于单例模式(Singleton)资源的锁

    不能调用不可重入的函数

    不能修改函数本身(除非执行在其专有的存储空间)

3、可重入函数与线程安全的函数

    线程安全的函数加入同步机制保护共享资源。所有的可重入函数都是线程安全的,反之不成立。

4、Linux的可重入函数

_exit & _Exit & exit*

abort*

accept

access

aio_error

aio_return

aio_suspend

alarm

bind

cfgetispeed

cfgetospeed

cfsetispeed

cfsetospeed

chdir

chmod

chown

clock_gettime

close

connect

creat

dup

dup2

execle

execve

fchmod

fchown

fcntl

fdatasync

fork

fpathconf

fstat

fsync

ftruncate

getegid

geteuid

getgid

getgroups

getpeername

getpgrp

getpid

getppid

getsockname

getsockopt

getuid

kill

link

listen

longjmp*

lseek

lstat

mkdir

mkfifo

open

pathconf

pause

pipe

poll

posix_trace_event

pselect

raise

read

readlink

recv

recvfrom

recvmsg

rename

rmdir

select

sem_post

send

sendmsg

sendto

setgid

setpgid

setsid

setsockopt

setuid

shutdown

sigaction

sigaddset

sigdelset

sigemptyset

sigfillset

sigismember

signal*

sigpause

sigpending

sigprocmask

sigqueue

sigset

sigsuspend

sleep

socket

socketpair

stat

symlink

sysconf

tcdrain

tcflow

tcflush

tcgetattr

tcgetpgrp

tcsendbreak

tcsetattr

tcsetpgrp

time

timer_getoverrun

timer_gettime

timer_settime

times

umask

uname

unlink

utime

wait

waitpid

write

  PS:以上函数的可重入性也不是绝对的(比如read,recv......都会修改errno)





你可能感兴趣的:(可重入函数)