简介Linux中的可重入函数和不可重入函数

可重入函数

可重入函数(即可以被中断的函数)可以被一个以上的任务调用,而不担心数据破坏。可重入函数在任何时候都可以被中断,而一段时间之后又可以恢复运行,而相应的数据不会破坏或者丢失。

可重入函数使用的变量有两种情况:

1.使用局部变量,变量保存在CPU寄存器中或者堆栈中;

2.使用全局变量,但是这时候要注意保护全局变量(防止任务中断后被其它任务改变变量)。

void strcpy(*dest,*src)
{
    while(* dest++ = *src ++){;}
    *dest = NUL;
}

分析:上面的函数用于字符串复制,而参数是存放在堆栈中的,故而改函数可以被多任务调用,而不必担心各个任务调用期间会互相破坏对方的指针。

基本上下面的函数都是不可重入的:

1.函数内使用了静态的数据。

2.函数内使用了malloc()或者free()函数的。

3.函数内调用了标准的I/O函数的。

int temp;
 void swap(int *ex1,int *ex2)
{
    temp = *ex1; //(1)
    *ex1 = *ex2;
    *ex2 = temp;
}

分析:该函数中的全局变量temp是的函数变成了一个不可重入的函数,因为在多任务系统中,假如在任务1中调用swap函数,而程序执行到(1)处时被中断,进而执行其它的任务2,而刚好任务2也调用了swap函数,则temp里存的值则会被任务2改变。从而回到任务1被中断处继续执行的时候,temp里存的值已经不再是原来存的temp值了,进而产生了错误。 常用的可重入函数的方法有:1.不要使用全局变量,防止别的代码覆盖这些变量的值。2.调用这类函数之前先关掉中断,调用完之后马上打开中断。防止函数执行期间被中断进入别的任务执行。3.使用信号量(互斥条件)。总之:要保证中断是安全的

不可重入函数

在多任务系统下,中断可能在任务执行的任何时间发生;如果一个函数的执行期间被中断后,到重新恢复到断点进行执行的过程中,函数所依赖的环境没有发生改变,那么这个函数就是可重入的,否则就不可重入。

在中断前后不都要保存和恢复上下文吗,怎么会出现函数所依赖的环境发生改变了呢?

我们知道中断时确实保存一些上下文,但是仅限于返回地址,cpu寄存器等之类的少量上下文,而函数内部使用的诸如全局或静态变量,buffer等并不在保护之列,所以如果这些值在函数被中断期间发生了改变,那么当函数回到断点继续执行时,其结果就不可预料了。

满足下面条件之一的多数是不可重入函数:

(1)使用了静态数据结构;

(2)调用了malloc或free;

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

(4)进行了浮点运算.

malloc/free是不可重入的,它们使用了全局变量来指向空闲区;标准I/O库的很多实现都使用了全局数据结构; 许多的处理器/编译器中,浮点一般都是不可重入的 (浮点运算大多使用协处理器或者软件模拟来实现)。

在信号处理程序及多线程编程时,要特别注意。

考虑这种情况:

1) 信号处理程序A内外都调用了同一个不可重入函数B;B在执行期间被信号打断,进入A (A中调用了B),完事之后返回B被中断点继续执行,这时B函数的环境可能改变,其结果就不可预料了。

2) 多线程共享进程内部的资源,如果两个线程A,B调用同一个不可重入函数F,A线程进入F后,线程调度,切换到B,B也执行了F,那么当再次切换到线程A时,其调用F的结果也是不可预料的。

在信号处理程序中即使调用可重入函数也有问题要注意。作为一个通用的规则,当在信号处理程序中调用可重

入函数时,应当在其前保存errno,并在其后恢复errno。(要了解经常被捕捉到的信号是SIGCHLD,其信号处理程序通常要调用一种wait函数,而各种wait函数都能改变errno。)

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索调用函数
, 函数
, 变量
, 程序
, 信号处理
, 可重入
, 信号量 条件变量
, 全局
, 不可预料的值
, 任务变量
, 任务
, 可重入锁
可重入锁RLock
嵌入式linux简介、linux 入口函数、linux内核入口函数、linux 可重入函数、linux简介,以便于您获取更多的相关知识。

时间: 2024-10-04 00:29:28

简介Linux中的可重入函数和不可重入函数的相关文章

简介Linux中cp和mv搭配{,}在shell当中的用法

  这篇文章主要介绍了简介Linux中cp和mv搭配{,}在shell当中的用法,作者举了四个这样的大括号扩展示例,需要的朋友可以参考下 经常会在博客或者论坛看到类似下面的命令 大括号扩展 Brace expansion { } shell 作用 ? 1 cp /etc/httpd/httpd.{,.bakup} 或者是 ? 1 mv resume{z,}.doc 那么,在uinx / linux shell命令中是什么意思?起什么作用呢? { } 并没有什么实际的含义,但是却可以作为Brace

简介Linux中cp和mv搭配{,}在shell当中的用法_linux shell

经常会在博客或者论坛看到类似下面的命令 大括号扩展  Brace expansion  {     }  shell   作用 cp /etc/httpd/httpd.{,.bakup} 或者是 mv resume{z,}.doc 那么,在uinx / linux  shell命令中是什么意思?起什么作用呢? {  } 并没有什么实际的含义,但是却可以作为Brace expansion(大括号扩展或叫做花括号扩展)而经常用于产生各种组个.以下是翻译自 GNU/BASH  man page  的内

fork() 函数与 Linux 中的多线程编程

一.fork()函数 在操作系统的基本概念中进程是程序的一次执行,且是拥有资源的最小单位和调度单位(在引入线程的操作系统中,线程是最小的调度单位).在Linux系统中 创建进程有两种方式:一是由操作系统创建,二是由父进程创建进程(通常为子进程).系统调用函数fork()是创建一个新进程的唯一方式,当然 vfork()也可以创建进程,但是实际上其还是调用了fork()函数.fork()函数是Linux系统中一个比较特殊的函数,其一次调用会有两个返 回值,下面是fork()函数的声明: #inclu

Linux 中的静态库和动态库简介及生成过程示例

在实际的软件开发项目中,不是每一行代码都需要我们亲自写.在我们的软件产品中,有一些代码(尤其是函数)的出现频率很高,它们可以被当作公共代码来反复使用.为了避免重复劳动,我们就把这些公共代码编译为库文件,供需要的程序调用.在Linux中,库分为静态库和动态库两种. 本文对静态库和动态库进行了详细的介绍,并用实际的C代码演示了这两种库的生成过程. 一.静态库和动态库简介 众所周知,程序一般需要经过预处理.编译.汇编和链接这几个步骤才能变成可执行的程序.在实际的软件开发中,对于一些需要被许多模块反复使

求助高手DataGridView的问题 (操作无效,原因是它导致对 SetCurrentCellAddressCore 函数的可重入调用。)

问题描述 voidHandleReceive(inteventID,stringdate,stringtime,intdspID,stringmessage,Imagei1,Imagei2){while(alertTable.Rows.Count>=50)//DataGridView中的报警信息超过50条就删除第一条,不断地往上顶{alertTable.Rows[0].Delete();}DataRowdr=alertTable.NewRow();dr[0]=eventID.ToString()

Linux中的静态库和动态库简介及生成过程示例

[文章摘要] 在实际的软件开发项目中,不是每一行代码都需要我们亲自写.在我们的软件产品中,有一些代码(尤其是函数)的出现频率很高,它们可以被当作公共代码来反复使用.为了避免重复劳动,我们就把这些公共代码编译为库文件,供需要的程序调用.在Linux中,库分为静态库和动态库两种. 本文对静态库和动态库进行了详细的介绍,并用实际的C代码演示了这两种库的生成过程. 一.静态库和动态库简介 众所周知,程序一般需要经过预处理.编译.汇编和链接这几个步骤才能变成可执行的程序.在实际的软件开发中,对于一些需要被

可重入函数与不可重入函数

主要用于多任务环境中,一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误:而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下的. 也可以这样理解,重入即表示重复进入,首先它意味着这个函数可以被中断,其次意味着它除了使用自己栈上的变量以外不依赖于任何环境(包括static),这样的函数就是purecode(

Linux中system函数的实现

#include <errno.h> #include <signal.h> #include <unistd.h> int system(const char *cmdstring) /* with appropriate signal handling */ { pid_t pid; int status; struct sigaction ignore, saveintr, savequit; sigset_t chldmask, savemask; if (cm

linux中exit()和_exit()函数的作用

exit和_exit函数都是用来终止进程的.当程序执行到exit或_exit时,系统无条件的停止剩下所有操作, 清除包括PCB在内的各种数据结构,并终止本进程的运行.但是,这两个函数是有区别的. exit()函数的作用是:直接使用进程停止运行,清除其使用的内存空间,并清除其在内核中的各种数据 结构:_exit()函数则在这一基础上做了一些包装.在执行退出之前加了若干道工序.exit()函数与_exit()函 数最大区别就在于exit()函数在调用exit系统之前要检查文件的打开情况,把文件缓冲区