在实时系统的设计中,经常会出现多个任务调用同一个函数的情况。如果有一个函数不幸被设计成为这样:那么不同任务调用这个函数时可能修改其他任务调用这个函数的数据,从而导致不可预料的后果。这样的函数是不安全的函数,也叫不可重入函数

相反,肯定有一个安全的函数,这个安全的函数又叫可重入函数。那么什么是可重入函数呢?所谓可重入是指一个可以被多个任务调用的过程,任务在调用时不必担心数据是否会出错。

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

也可以这样理解,重入即表示重复进入,首先它意味着这个函数可以被中断,其次意味着它除了使用自己栈上的变量以外不依赖于任何环境(包括 static),这样的函数就是purecode(纯代码)可重入,可以允许有该函数的多个副本在运行,由于它们使用的是分离的栈,所以不会互相干扰。如果确实需要访问全局变量(包括 static),一定要注意实施互斥手段。可重入函数在并行运行环境中非常重要,但是一般要为访问全局变量付出一些性能代价。

编写可重入函数时,若使用全局变量,则应通过关中断、信号量(即P、V操作)等手段对其加以保护。

说明:若对所使用的全局变量不加以保护,则此函数就不具有可重入性,即当多个进程调用此函数时,很有可能使有关全局变量变为不可知状态。

示例:假设 Exam 是 int 型全局变量,函数 Squre_Exam 返回 Exam 平方值。那么如下函数不具有可重入性。

int Exam = 0;
unsigned int example( int para )
{ unsigned int temp;Exam = para; // (**)temp = Square_Exam( );return temp;
}

此函数若被多个进程调用的话,其结果可能是未知的,因为当(**)语句刚执行完后,另外一个使用本函数的进程可能正好被激活,那么当新激活的进程执行到此函数时,将使 Exam 赋与另一个不同的 para 值,所以当控制重新回到 “temp = Square_Exam( )” 后,计算出的temp很可能不是预想中的结果。此函数应如下改进。

int Exam = 0;
unsigned int example( int para )
{unsigned int temp;[申请信号量操作] //(1)  加锁Exam = para;ten temp;
}mp = Square_Exam( );[释放信号量操作] //     解锁 retur



申请不到“信号量”,说明另外的进程正处于给 Exam 赋值并计算其平方过程中(即正在使用此信号),本进程必须等待其释放信号后,才可继续执行。若申请到信号,则可继续执行,但其它进程必须等待本进程释放信号量后,才能再使用本信号。

保证函数的可重入性的方法:

1)在写函数时候尽量使用局部变量(例如寄存器、堆栈中的变量);

2)对于要使用的全局变量要加以保护(如采取关中断、信号量等互斥方法),这样构成的函数就一定是一个可重入的函数。

满足下列条件的函数多数是不可重入(不安全)的:
1)函数体内使用了静态的数据结构;
2)函数体内调用了malloc() 或者 free() 函数;
3)函数体内调用了标准 I/O 函数。
如何将一个不可重入的函数改写成可重入函数呢?把一个不可重入函数变成可重入的唯一方法是用可重入规则来重写它。其实很简单,只要遵守了几条很容易理解的规则,那么写出来的函数就是可重入的:
1)不要使用全局变量。因为别的代码很可能改变这些变量值。
2)在和硬件发生交互的时候,切记执行类似 disinterrupt() 之类的操作,就是关闭硬件中断。完成交互记得打开中断,在有些系列上,这叫做“进入/ 退出核心”。
3)不能调用其它任何不可重入的函数。
4)谨慎使用堆栈。

Linux常见的可重入函数

参考资料:http://www.embeddedlinux.org.cn

【Linux系统编程】可重入函数和不可重入函数相关推荐

  1. Linux系统编程34:进程信号之可重入函数,volatile关键字的作用和SIGHLD

    文章目录 (1)可重入函数 (2)volatile关键字 A:背景知识 B:产生的问题 C:volatile关键字 (3)SIGHLD信号 A:复习僵尸进程 B:清理僵尸状态的新方法-SIGCHLD ...

  2. Linux系统编程之进程控制(进程创建,fork函数,进程中止,进程等待,程序替换)

    进程创建 fork()------复制,返回值,写时复制 vfork()创建子进程-子进程与父进程共用同一块虚拟地址空间, 为了防止调用栈混乱,因此阻塞父进程直到子进程调用exit()退出或者进行程序 ...

  3. linux系统编程之进程(五):exec系列函数(execl,execlp,execle,execv,execvp)使用

    本节目标: exec替换进程映像 exec关联函数组(execl.execlp.execle.execv.execvp) 一,exec替换进程映像 在进程的创建上Unix采用了一个独特的方法,它将进程 ...

  4. linux系统发送信号的系统调用是,linux系统编程之信号:信号发送函数sigqueue和信号安装函数sigaction...

    信号发送函数sigqueue和信号安装函数sigaction sigaction函数用于改变进程接收到特定信号后的行为. sigqueue()是比较新的发送信号系统调用,主要是针对实时信号提出的(当然 ...

  5. 【README】Linux系统编程必读:本专栏内容提要以及系统调用接口总结

    文章目录 前言 第一部分:博客知识点 (1)基础篇 Linux系统编程1:Linux中使用率最高的一些命令 Linux系统编程2:详解Linux中的权限问题 Linux系统编程3:基础篇之详解Linu ...

  6. 【Linux系统编程】vfork() 函数详解

    00. 目录 文章目录 00. 目录 01. vfork函数 02. fork和vfork区别 03. 父子进程地址空间 04. 附录 01. vfork函数 函数分析 #include <sy ...

  7. 【Linux系统编程】fork()函数详解

    00. 目录 文章目录 00. 目录 01. 进程创建函数 02. 父子进程结构 03. 父子进程地址空间 04. 附录 01. 进程创建函数 #include <sys/types.h> ...

  8. linux系统编程之文件与I/O(六):fcntl 函数与文件锁

    2013-05-14 11:26 8290人阅读 评论(2) 收藏 举报  分类: linux系统编程(19)  版权声明:本文为博主原创文章,未经博主允许不得转载. 一.fcntl函数 功能:操纵文 ...

  9. linux系统编程学习_(2)进程控制-- fork函数、exec函数族、回收子进程--孤儿进程僵尸进程、wait函数

    linux系统编程学习_(2)进程控制-- fork函数.exec函数族.回收子进程–孤儿进程僵尸进程.wait函数 进程控制 fork()函数 创建一个子进程. pid_t fork(void); ...

  10. Linux系统编程 37 -makefile2个函数和clean

    Linux系统编程 37 -makefile2个函数和clean 学习笔记 一个makefile 就是用一个个规则凑在一起 2个函数 wildcard patsubst wildcard 百搭牌,通配 ...

最新文章

  1. AI芯片结构目标图形处理
  2. Maven 私服搭建指南
  3. Model层视频播放关闭问题及手机视频播放的适配问题解决方案
  4. 树形结构与关系数据库之闭包表
  5. 【工程项目经验】之Xcode的Instruments检测解决iOS内存泄露
  6. 应届生找工作是首先选择一个公司,还是选择一个行业?
  7. 十年数据分析经验,总结出这三类分析工具最好用
  8. 鸿蒙应用开发 | 时间选择器(TimePicker)的功能和用法
  9. Linux加密框架中的算法和算法模式(2)——模式介绍
  10. JAVA基础之Http协议
  11. Springboot+bootstrap+thymeleaf+shiro项目《晨光房屋在线租赁》
  12. Python 爬虫---初窥门径
  13. 奈奎斯特定理和香农定理解释
  14. 20200509 Curator入门
  15. 蓝牙配对-扫描-连接-状态查询
  16. Python爬取笔趣阁小说,有趣又实用!
  17. java properties map_为什么java.util.Properties实现Map而不是Map
  18. python-图片上添加字符
  19. Interview100-91 著名的毒酒问题
  20. redis如何清空指定缓存和所有缓存

热门文章

  1. UML小结以及基于领域模型的系统设计初步
  2. java:区间k大数查询
  3. linux文件的打包与下载总结,linux下文件的打包和压缩
  4. arp 不同网段 相同vlan_三层交换机,相同的网段,不同的VLAN ,怎么通信?
  5. url能访问但new file()找不到文件_Go Web编程给自己写的服务器添加错误和访问日志...
  6. 3.定义一个有10个元素的数组,用其代表10个学生的考试成绩,从键盘输入10个成绩,统计平均成绩。
  7. Unity性能优化-遮挡剔除
  8. windows2016 安装mysql5.7
  9. 查看APK中MD5签名的方法
  10. BZOJ2005: [Noi2010]能量采集 莫比乌斯反演的另一种方法——nlogn筛