一. 不可重入函数

  1.1. 什么是不可重入函数

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

  1.2. 不可重入函数产生

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

      a. 函数体内使用了静态的数据结构;

      b. 函数体内调用了malloc()或者free()函数(malloc和free为不可重入函数);

      c. 函数体内调用了标准I/O函数。

二. 可重入函数

  2.1. 什么是可重入函数

    a. 可重入函数可以被一个以上的任务调用,而不必担心数据被破坏。可重入函数任何时候都可以被中断,一段时间以后又可以运行,而相应的数据不会丢失。可重入函数或者只使用局部变量,即保存在CPU寄存器中或堆栈中;或者使用全局变量,则要对全局变量予以保护

  2.2. 如何写出可重入函数

    a. 在函数体内不访问那些全局变量,不使用静态局部变量,坚持只使用缺省态(auto)局部变量,写出的函数就将是可重入的。如果必须访问全局变量,记住利用互斥信号量来保护全局变量。或者调用该函数前关中断,调用后再开中断。

三. 实例分析

   假设 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;  
    temp = Square_Exam( );  
    [释放信号量操作] //     解锁   
    return temp;  
}

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