`

可重入(reentrant)

    博客分类:
  • c++
 
阅读更多
在文档中多次出现reentrant,一直没弄清楚这个东东,现在明白了,其实简单说在函数中也就是相同输入能保证结果相同。
原文:
http://blog.chinaunix.net/space.php?uid=11211848&do=blog&id=2895580 
在实时系统的设计中,经常会出现多个任务调用同一个函数的情况。如果这个函数不幸被设计成为不可重入的函数的话,那么不同任务调用这个函数时可能修改其他 任务调用这个函数的数据,从而导致不可预料的后果。那么什么是可重入函数呢?所谓可重入函数是指一个可以被多个任务调用的过程,任务在调用时不必担心数据 是否会出错。不可重入函数在实时系统设计中被视为不安全函数。满足下列条件的函数多数是不可重入的:
    1) 函数体内使用了静态的数据结构;
    2) 函数体内调用了malloc()或者free()函数;
    3) 函数体内调用了标准I/O函数。

    下面举例加以说明。
    A. 可重入函数
    void strcpy(char *lpszDest, char *lpszSrc) {
        while(*lpszDest++=*lpszSrc++);
        *dest=0;
    }

    B. 不可重入函数1
    charcTemp;//全局变量
    void SwapChar1(char *lpcX, char *lpcY) {
        cTemp=*lpcX;
        *lpcX=*lpcY;
        lpcY=cTemp;//访问了全局变量
    }

    C. 不可重入函数2
    void SwapChar2(char *lpcX,char *lpcY) {
        static char cTemp;//静态局部变量
        cTemp=*lpcX;
        *lpcX=*lpcY;
        lpcY=cTemp;//使用了静态局部变量
    }

    问题1,如何编写可重入的函数?
    答:在函数体内不访问那些全局变量,不使用静态局部变量,坚持只使用局部变量,写出的函数就将是可重入的。如果必须访问全局变量,记住利用互斥信号量来保护全局变量。

    问题2,如何将一个不可重入的函数改写成可重入的函数?
    答:把一个不可重入函数变成可重入的唯一方法是用可重入规则来重写它。其实很简单,只要遵守了几条很容易理解的规则,那么写出来的函数就是可重入的。
    1) 不要使用全局变量。因为别的代码很可能覆盖这些变量值。
    2) 在和硬件发生交互的时候,切记执行类似disinterrupt()之类的操作,就是关闭硬件中断。完成交互记得打开中断,在有些系列上,这叫做“进入/退出核心”。
    3) 不能调用其它任何不可重入的函数。
    4) 谨慎使用堆栈。最好先在使用前先OS_ENTER_KERNAL。

    堆栈操作涉及内存分配,稍不留神就会造成益出导致覆盖其他任务的数据,所以,请谨慎使用堆栈!最好别用!很多黑客程序就利用了这一点以便系统执行非法代码从而轻松获得系统控制权。还有一些规则,总之,时刻记住一句话:保证中断是安全的!

    实例问题:曾经设计过如下一个函数,在代码检视的时候被提醒有bug,因为这个函数是不可重入的,为什么?
    unsigned int sum_int( unsigned int base ) {
        unsigned int index;
        static unsigned int sum = 0; // 注意,是static类型
        for (index = 1; index <= base; index++)
            sum += index;
        return sum;
    }

    分析:所谓的函数是可重入的(也可以说是可预测的),即只要输入数据相同就应产生相同的输出。这个函数之所以是不可预测的,就是因为函数中使用了 static变量,因为static变量的特征,这样的函数被称为:带“内部存储器”功能的的函数。因此如果需要一个可重入的函数,一定要避免函数中使用 static变量,这种函数中的static变量,使用原则是,能不用尽量不用。
    将上面的函数修改为可重入的函数,只要将声明sum变量中的static关键字去掉,变量sum即变为一个auto类型的变量,函数即变为一个可重入的函数。
    当然,有些时候,在函数中是必须要使用static变量的,比如当某函数的返回值为指针类型时,则必须是static的局部变量的地址作为返回值,若为auto类型,则返回为错指针。
分享到:
评论

相关推荐

    recursive-and-reentrant-VI.zip_labview可重入VI_non-reentrant VI_vi

    相比之下,非可重入VI(non-reentrant VI)在同一时间只能被一个任务调用,如果多个任务尝试同时访问,可能会导致数据不一致或者程序挂起。 再来看看"For structure.vi",这是LabVIEW中的循环结构,用于执行一系列...

    LabVIEW中可重入VI设置范例

    在LabVIEW(Laboratory Virtual Instrument Engineering Workbench)中,可重入VI(Reentrant VI)是一种特殊类型的虚拟仪器,设计用于解决多线程环境下的并发访问问题,确保数据的完整性和程序的正确运行。...

    可重入详解可重入详解

    在计算机科学领域中,“可重入”(reentrant 或 re-entrant)是一个重要的概念,尤其在多线程编程和并发环境中尤为关键。如果一个程序或者子程序能够被安全地并行执行,那么我们称这个程序或子程序为“可重入”的。...

    LabVIEW中异步调用+可重入VI设置

    例如,"Asynchronous Call(Reentrant)"这个文件可能是这样的一个示例,演示了如何设计一个既支持异步调用又具有可重入性的VI。在学习这些实例时,建议仔细分析代码结构,理解每个部分的作用,尤其是事件结构、回调VI...

    5.如何使用 VI 的重入属性(Reentrant).doc-综合文档

    在LabVIEW编程环境中,VI(Virtual Instrument)的重入属性(Reentrant)是一个重要的概念,尤其是在多线程和并发执行的场景下。本篇将详细解释如何使用VI的重入属性,以及它在不同情况下的作用。 重入属性在VI ...

    Linux 中可重入函数与不可重入函数详解

    在Linux操作系统中,可重入函数(Reentrant Function)和不可重入函数(Non-reentrant Function)是编程中两个非常重要的概念,特别是在多线程和并发编程中。它们的特性决定了它们在处理并发请求时的行为差异,对于...

    Zookeeper 分布式重入排它锁实现

    **分布式重入排他锁(Reentrant Lock)在Zookeeper中的实现** Zookeeper是一个开源的分布式协调服务,常用于分布式环境中的一致性问题,如配置管理、命名服务、分布式同步等。在分布式系统中,为了保证数据的一致性...

    uCOS51 重入问题的解决.pdf

    标题和描述中提到的“uCOS51 重入问题的解决”,主要聚焦于解决uCOS51(一种基于8051微控制器的实时操作系统)在特定条件下遇到的重入性问题。重入性是指一个函数或子程序能够被多个任务或线程同时调用而不会产生...

    keilc51可重入函数及模拟栈浅析

    【可重入函数的实现】在Keil C51中,可以通过在函数定义时添加`reentrant`关键字来标记函数为可重入的。这样编译器会在函数调用时使用模拟栈来保存和恢复函数的状态,确保即使在中断或并发调用时,函数的数据也不会...

    zookeeper分布式锁实例源码

    2. **可重入锁(Reentrant Lock)**: 可重入锁允许持有锁的线程多次进入同一锁保护的代码块。在ZooKeeper中,为了实现可重入性,我们需要额外记录锁的持有者信息,比如线程ID。每次线程请求锁时,检查当前持有者...

    线程安全详解及相关实用技巧(附源码)

    如果一个函数间接调用了非可重入的函数,那么整个调用链路都不是可重入的。 (四) 使用了同步机制的函数,是不可重入的 虽然同步机制如互斥量和信号量可以用来保护资源,但它们自身不是可重入的,因为它们依赖于全局...

    Linux多线程编程问题[归类].pdf

    - **不可重入函数**:那些返回与输入参数无关的数据且无需释放的函数,如`gmtime`、`ntoa`、`gethostbyname`等,通常是不可重入的,因为它们可能依赖全局状态。 4. **识别重入问题**: - 识别不可重入函数的规则...

    举例讲解Python中的死锁、可重入锁和互斥锁

    为了解决死锁问题,Python提供了一种特殊的锁类型——**可重入锁**(Reentrant Lock,简称RLock),它允许在同一线程中多次获取同一把锁。RLock内部维护了一个计数器,用于记录当前线程获取锁的次数。只有当一个线程...

    ZKRecipesByExample, 管理员食谱的所有示例.zip

    ZKRecipesByExample, 管理员食谱的所有示例 ZKRecipesByExample管理员食谱的所有示例。 leader选举 latch latch latch 分布式锁 可重入锁Shared Reentrant Lock 不可重入锁Shared Lock 可重

    子函数同时被中断函数和主函数

    问题的根源在于,子函数可能会被同时调用,而这个函数不是可重入的。这意味着,如果这个函数已经在执行时,它可能被另一个ISR(Interrupt Service Routine,中断服务程序)所调用。这将导致结果不可预测,并且可能会...

    UNIX-编程中错误输出的线程安全问题.pdf

    另一种方法是使用可重入(reentrant)函数,如带 `_r` 后缀的函数,它们设计成可以安全地在多线程环境下使用,不会干扰其他线程的执行。此外,像`malloc`和`free`这样的内存管理函数也是线程安全的,尽管它们不是可...

    单片机C语言开发五.ppt

    在C51编程环境下,函数的定义有了更丰富的形式,包括模式选择(如`small`、`compact`、`large`)、可重入性(`reentrant`)以及指定使用特定寄存器组(`using n`)。模式选择通常在项目设置中确定,但也可以在函数...

    sync-master.zip

    首先,分布式可重入互斥锁(Distributed Reentrant Mutex Lock)是一种确保同一时间只有一个线程执行特定代码块的机制。在分布式系统中,这种锁能够防止多个节点同时访问共享资源,从而避免数据不一致性和竞态条件。...

    Java多线程并发编程(互斥锁Reentrant Lock)

    2. 可重入锁:ReentrantLock 是可重入锁,即某一线程可以多次获得该锁。 3. 公平锁和非公平锁:ReentrantLock 可以选择实例化一个公平锁或非公平锁,默认情况下会构造一个非公平锁。公平锁可以确保有序性(FIFO 队列...

    Python应用实战:python多线程-多线程安全问题&lock与rlock.zip

    除了基本的锁,Python还提供了可重入锁(Reentrant Lock),也就是`threading.RLock`。可重入锁允许同一个线程多次获取锁,这在某些场景下非常有用,比如在递归函数中。如果一个线程已经持有了一个可重入锁,它依然...

Global site tag (gtag.js) - Google Analytics