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

一、 POSIX 中对可重入和线程安全这两个概念的定义:

Reentrant Function:A function whose effect, when called by two or more threads,is guaranteed to be as if

the threads each executed the function one after another in an undefined order, even if the actual execution is interleaved.

Thread-Safe Function:A function that may be safely invoked concurrently by multiple threads.

Async-Signal-Safe Function: A function that may be invoked, without restriction from signal-catching functions. No function is async-signal -safe unless explicitly described as such.

以上三者的关系为:可重入函数 必然 是 线程安全函数 和 异步信号安全函数; 线程安全函数不一定是可重入函数。

可重入与线程安全的区别体现在能否在signal处理函数中被调用的问题上,可重入函数在signal处理函数中可以被安全调用,因此同时也是Async-Signal-Safe Function;而线程安全函数不保证可以在signal处理函数中被安全调用,如果通过设置信号阻塞集合等方法保证一个非可重入函数不被信号中断,那么它也是Async-Signal-Safe Function。

举个例子,strtok是既不可重入的,也不是线程安全的;加锁的strtok不是可重入的,但线程安全;而strtok_r既是可重入的,也是线程安全的。也就是说函数如果使用静态变量,通过加锁后可以转成线程安全函数,但仍然有可能不是可重入的。我们所熟知的alloc也是线程安全但不是可重入的。

再举个例子,假设函数func()在执行过程中需要访问某个共享资源,因此为了实现线程安全,在使用该资源前加锁,在不需要资源解锁。 假设该函数在某次执行过程中,在已经获得资源锁之后,有异步信号发生,程序的执行流转交给对应的信号处理函数;再假设在该信号处理函数中也需要调用函数 func(),那么func()在这次执行中仍会在访问共享资源前试图获得资源锁,然而我们知道前一个func()实例已然获得该锁,因此信号处理函数阻塞;另一方面,信号处理函数结束前被信号中断的线程是无法恢复执行的,当然也没有释放资源的机会,这样就出现了线程和信号处理函数之间的死锁局面。

因此,func()尽管通过加锁的方式能保证线程安全,但是由于函数体对共享资源的访问,因此是非可重入。

对于这种情况,采用的方法一般是在特定的区域屏蔽一定的信号。

二、可重入函数

我们知道,当捕捉到信号时,不论进程的主控制流程当前执行到哪儿,都会先跳到信号处理函数中执行,从信号处理函数返回后再继续执行主控制流程。信号处理函数是一个单独的控制流程,因为它和主控制流程是异步的,二者不存在调用和被调用的关系,并且使用不同的堆栈空间。引入了信号处理函数使得一个进程具有多个控制流程,如果这些控制流程访问相同的全局资源(全局变量、硬件资源等),就有可能出现冲突,如下面的例子所示。

时间: 2024-10-30 07:30:23

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

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

可重入函数 可重入函数(即可以被中断的函数)可以被一个以上的任务调用,而不担心数据破坏.可重入函数在任何时候都可以被中断,而一段时间之后又可以恢复运行,而相应的数据不会破坏或者丢失. 可重入函数使用的变量有两种情况: 1.使用局部变量,变量保存在CPU寄存器中或者堆栈中: 2.使用全局变量,但是这时候要注意保护全局变量(防止任务中断后被其它任务改变变量). void strcpy(*dest,*src) { while(* dest++ = *src ++){;} *dest = NUL; }

【Linux】可重入函数和线程安全的区别与联系【转】

转自:http://blog.csdn.net/scenlyf/article/details/52074444 版权声明:本文为博主原创文章,未经博主允许不得转载. *****可重入函数       函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入.       当程序运行到某一个函数的时候,可能因为硬件中断或者异常而使得在用户正在执行的代码暂时终端转而进入你内核,这个时候如有一个信号需要被处理,而处理的这个信号的时候又会重新调用刚才中断的函数,如果函数内部有

什么是可重入函数

什么叫可重入: 可重入是一个并发下才有的概念.如果说,程序是串行的,自然也就不会有可重入这回事了.因为并发,所以任何个步骤都可能在运行中途被中断,然后跑另一个代码.这样就会出现一种可能,比如说两段代码都操作了一个全局变量,就会造成意想不到的错误. 可重入函数指的是,有多个线程在并发的执行一个函数.这个时候,如果两个函数会操作同一个全局的变量.这就是上面说的场景了. 什么样的函数不可重入: 函数体内使用了静态的数据结构(全局变量等). 函数体内调用了malloc()或者free()函数. 函数体内

2信号处理之:信号产生原因,进程处理信号行为,信号集处理函数,PCB的信号集,sigprocmask()和sigpending(),信号捕捉设定,sigaction,C标准库信号处理函数,可重入函数,

 1信号产生原因 2.进程处理信号行为 manpage里信号3中处理方式: SIG_IGN SIG_DFL                                            默认Term动作 a signal handling function 进程处理信号 A默认处理动作 term   中断 core    core(调试的时候产生) gcc –g file.c     ulimit –c 1024     gdb a.out core ign      忽略 stop

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

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

Linux多线程可重入函数

Reentrant和Thread-safe 在单线程程序中,整个程序都是顺序执行的,一个函数在同一时刻只能被一个函数调用,但在多线程中,由于并发性,一个函数可能同时被多个函数调用,此时这个函数就成了临界资源,很容易造成调用函数处理结果的相互影响,如果一个函数在多线程并发的环境中每次被调用产生的结果是不确定的,我们就说这个函数是"不可重入的"/"线程不安全"的.为了解决这个问题,POSIX多线程库提出了一种机制,用来解决多线程环境中的线程数据私有化问题,这套机制的主要

Linux shell编程基础 六、算术运算

算术运算 归纳为5种方法 1.算术扩展,例如R=$((1+1)) 2.使用外部程序expr,例如R=`expr 1+1` 3.使用$[],例如R=[1+1] 4.使用命令declare,例如declare -i R=1+1 5.使用命令let,例如let R=1+1

Linux编程:readn, writen和readline函数的调用

#include <unistd.h> #include <errno.h> ssize_t readn(int fd, void *buf, size_t count) { char *strtmp; ssize_t reval, realcount=0; strtmp = (char *)buf; while (count>0) { reval = read(fd, strtmp, count); if (reval<0) if (errno == EINTR) c

编程基础讲解 续 (预定义函数)

Flash 具有内置的函数,使您可以访问特定的信息,以及执行特定的任务,例如获得播放影片的 Flash Player 的版本号 (getVersion).属于对象的函数称为方法.不属于对象的函数称为顶级函数,可以在"动作"面板的"函数"类别中找到它们. 每个函数都有自己的特性,而且某些函数需要您传递特定的值.如果传递的参数多于函数的需要,多余的值将被忽略.如果不传递所需的参数,空的参数会被指定为 undefined 数据类型,在导出脚本时,可能会导致出现错误.要调用