可重入函数

2017-07-18  本文已影响0人  夏至亦韵

## 可重入函数

### 可重入性的理解

若一个程序或子程序可以安全的被并行执行,则称其为可重入的;即当该子程序正在运行时,可以再次进入并执行它。若一个函数是可重入的,则该函数必须满足一下必要条件:

1. 不能含有静态(全局)非常量数据。

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

3. 只能处理由调用者提供的数据。作为可重入函数的输入参数,只能由调用者提供,而且所提供的输入数据必须满足上面两点要求

4. 不能依赖于单实例模式资源的锁。

5. 不能调用不可重入的函数。

6. 函数内部,尽量不能用 malloc 和 free 之类的方法进行内存分配和释放,如果使用,一般情况下会造成该函数的不可重入.

可重入函数主要用于多任务环境中。可重入的函数必须满足以下三个条件:

(1)可以在执行的过程中可以被打断;

(2)被打断之后,在该函数一次调用执行完之前,可以再次被调用(或进入,reentered)。

(3)再次调用执行完之后,被打断的上次调用可以继续恢复执行,并正确执行。

### 不可重入函数的示例

如果一个函数只有调用者提供的非静态变量参数,并且函数中只依赖自己栈上的环境,也没有调用其他的不可重入函数,那么他就一定是可重入的.这样的函数就是purecode(纯代码)可重入,可以允许有该函数的多个副本在运行,由于它们使用的是分离的栈,所以不会互相干扰。如果确实需要访问全局变量(包括 static),一定要注意实施互斥手段。可重入函数在并行运行环境中非常重要,但是一般要为访问全局变量付出一些性能代价。

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

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

```cpp

int Exam = 0;

unsigned int example( int para )

{

unsigned int temp;

Exam = para; // (**)

temp = Square_Exam( );

return temp;

}

```

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

```cpp

view plaincopy在CODE上查看代码片派生到我的代码片

int Exam = 0;

unsigned int example( int para )

{

unsigned int temp;

[申请信号量操作] //(1)  加锁

Exam = para;

temp = Square_Exam( );

[释放信号量操作] //    解锁

return temp;

}

```

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

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

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

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

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

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

2. 函数体内调用了malloc() 或者 free() 函数;

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

上一篇下一篇

猜你喜欢

热点阅读