加入收藏 | 设为首页 | 会员中心 | 我要投稿 济南站长网 (https://www.0531zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

linux编程基础(六) 可重入函数、sig_atomic_t类型和volatile限定符

发布时间:2016-09-24 23:55:45 所属栏目:Linux 来源:站长网
导读:一、 POSIX 中对可重入和线程安全这两个概念的定义: Reentrant Function:A function whose effect, when called by two or more threads,is guaranteed to be

main函数调用insert函数向一个链表head中插入节点node1,插入操作分为两步,刚做完第一步的时候,因为硬件中断使进程切换到内核,再次回用户态之前检查到有信号待处理,于是切换到sighandler函数,sighandler也调用insert函数向同一个链表head中插入节点node2,插入操作的两步都做完之后从sighandler返回内核态,再次回到用户态就从main函数调用的insert函数中继续往下执行,先前做第一步之后被打断,现在继续做完第二步。结果是,main函数和sighandler先后向链表中插入两个节点,而最后只有一个节点真正插入链表中了。

像上例这样,insert函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入,insert函数访问一个全局链表,有可能因为重入而造成错乱,像这样的函数称为不可重入函数,反之,如果一个函数只访问自己的局部变量或参数,则称为可重入(Reentrant)函数。

不可重入函数的原因在于:

1> 已知它们使用静态数据结构

2> 它们调用malloc和free.

因为malloc通常会为所分配的存储区维护一个链接表,而插入执行信号处理函数的时候,进程可能正在修改此链接表。

3> 它们是标准IO函数.

因为标准IO库的很多实现都使用了全局数据结构

3、sig_atomic_t类型与volatile限定符

在上面的图示例子中,main和sighandler都调用insert函数则有可能出现链表的错乱,其根本原因在于,对全局链表的插入操作要分两步完成,不是一个原子操作,假如这两步操作必定会一起做完,中间不可能被打断,就不会出现错乱了。

关于原子操作最原始的说法是一条汇编指令能够完成(对于多线程程序来说原子操作可以指加锁后的几个步骤集合),即使是一条C语句也不一定是一个原子操作,比如 a = 5; 如果a是32位的int变量,在32位机上赋值是原子操作,在16位机上就不是。如果在程序中需要使用一个变量,要保证对它的读写都是原子操作,应该采用什么类型呢?

为了解决这些平台相关的问题,C标准定义了一个类型sig_atomic_t,在不同平台的C语言库中取不同的类型,例如在32位机上定义sig_atomic_t为int类型。

在使用sig_atomic_t类型的变量时,还需要注意另一个问题。看如下的例子:

#include <signal.h>

sig_atomic_t a=0;

int main(void)

{

/* register a sighandler */

while(!a); /* wait until a changes in sighandler */

/* do something after signal arrives *

/ return 0;

}

(编辑:济南站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读