信号之可重入函数、竞态条件

一、可重入函数

1.基本概念

  当捕捉到信号时,不论进程的主控制流程当前执行到哪儿,都会先跳到信号处理函数中执行,从 信号处理函数返回后再继续执行主控制流程。信号处理函数是一个单独的控制流程,因为它 和主控制流程是异步的,二者不存在调⽤用和被调⽤用的关系,并且使用不同的堆栈空间。引入了 信号处理函数使得一个进程具有多个控制流程,如果这些控制流程访问相同的全局资源(全局 变量、硬件资源等),就有可能出现冲突。
     函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次 进入该函 数,这称为重入,insert函数访问一个全局链表,有可能因为重入而造成错乱,像这样 的函数称为 不可重入函数,反之,如果一个函数只访问自己的局部变量或参数,则称为可重入 (Reentrant) 函数。
对于不可重入函数:
     1.调用了malloc或free
     2.调用了标准I/O库函数
2.可重入函数与线程安全
线程安全定义:如果代码所在进程中有多个线程同时运行,而这些线程可能同时运行这段代码,若每次运行和单线程运行时结果一样,且其他变量与预期结果也是一样的,则是线程安全的。
线程不安全的函数:
  • 不保护共享变量的函数;
  • 函数状态随着调用改变的函数;
  • 返回指向静态变量指针的函数;
  • 调用线程不安全函数的函数
对于可重入函数与线程安全对比:
可重入和线程安全(Thread-Safe)是两个不同的概念:可重入函数一定是线程安全的;线程安全的函数可能是重入的,也可能是不重入的;线程不安全的函数一定是不可重入的。
可重入函数要解决的问题是,不在函数内部使用静态或全局数据,不返回静态或全局数据,也不调用不可重入函数。

线程安全函数要解决的问题是,多个线程调用函数时访问资源冲突。

函数如果使用静态变量,通过加锁后可以转成线程安全函数,但仍然有可能不是可重入的。

二、竞态条件与sigsuspend函数

     在上面自己定义的my_sleep函数中,如果闹钟刚设定完毕进程被切出去,操作系统发出闹钟信号后进程才被切进来继续,这样pause函数执行则不能接收到alarm信号
     这个问题的根本原因是系统运行的时序问题。虽然alarm紧接着下面就是pause,但是还是无法保证pause函数一定会调用alarm设定时间内调用。
     像这类由于时序问题导致的错误,叫做竞态条件。
     sigsuspend解决了竟态条件的问题,它能够使“解除信号屏蔽”和“挂起等待信号”合并成一个原子操作。所以在对时序要求严格的场合下都应该调用sigsuspend而不是pause

  调⽤用sigsuspend时,进程的信号屏蔽字由sigmask参数指定,可以通过指定sigmask来临时 解除对某 个信号的屏蔽,然后挂起等待,当sigsuspend返回时,进程的信号屏蔽字恢复为原 来的值,如果原来对该信号是屏蔽的,从sigsuspend返回后仍然是屏蔽的。 
三、SIGCHILD信号
     子进程在终止时会给父进程发送SIGCHILD信号,该信号的默认处理动作是忽略,父进程可以自定义SIGCHILD函数。子进程在终止时会通知父进程,父进程在信号处理函数中调用wait清理子进程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值