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    
停止

cont    
继续

B忽略

C捕捉(用户自定义处理函数)

3信号集处理函数

sigset_t为信号集,可sizeof(sigset_t)查看

将信号集里面的每位都置0

int sigemptyset(sigset_t *set)

将所有信号集都置1

int sigfillset(sigset_t *set)

添加一个信号,也就是将Block阻塞信号集里面的某一位置成1

int sigaddset(sigset_t *set, int signo)

将信号集中某一位取消置1

int sigdelset(sigset_t *set, int signo)

测试某个信号集中的信号是否为1

int sigismember(const sigset_t *set, intsigno)

4 PCB的信号集

信号在内核中的表示示意图

如果在进程解除对某信号的阻塞之前这种信号产生过多次,将如何处理?POSIX.1允

许系统递送该信号一次或多次。Linux是这样实现的:常规信号在递达之前产生多次只

计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。本章不讨论实时信

号。从上图来看,每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少

次,阻塞标志也是这样表示的。因此,未决和阻塞标志可以用相同的数据类型sigset_t

来存储,sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态,

在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有

效”和“无效”的含义是该信号是否处于未决状态。

阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解

为阻塞而不是忽略。

5sigprocmask

调用函数sigprocmask可以读取或更改进程的信号屏蔽字。

依赖的头文件:

#include <signal.h>

函数声明:

*set是传入的信号,*oset表示原来的信号集是什么,相当于是*set的一个备份

intsigprocmask(int how, const sigset_t *set, sigset_t *oset);         

返回值:若成功则为0,若出错则为-1

如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都是非空指针,则先将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。

   
how参数的含义

SIG_BLOCK set包含了我们希望添加到当前信号屏蔽字的信号,相当于mask=mask|set

SIG_UNBLOCK set包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当于mask=mask&~set

SIG_SETMASK
设置当前信号屏蔽字为set所指向的值,相当于mask=set

6sigpending(未决打印信号)

#include<signal.h>

int sigpending(sigset_t *set)

sigpending读取当前进程的未决信号集,通过set参数传出。调用成功则返回0,出错则

返回-1。

6案例说明:

运行结果:

程序运行时,每秒钟把各信号的未决状态打印一遍,由于我们阻塞了SIGINT信号,按Ctrl-C将会使SIGINT信号处于未决状态,按Ctrl-\仍然可以终止程序,因为SIGQUIT信号没有阻塞。

这时按Ctrl+\结束。

7信号捕捉设定

8.sigaction

#include <signal.h>

int sigaction(int signum, const structsigaction *act,

struct sigaction *oldact);

 

struct sigaction
定义:

struct sigaction {

void (*sa_handler)(int);

void (*sa_sigaction)(int, siginfo_t *, void *);

sigset_t sa_mask;

int sa_flags;

void (*sa_restorer)(void);

};

sa_handler:早期的捕捉函数

sa_sigaction :
新添加的捕捉函数,可以传参,和sa_handler互斥,两者通过sa_flags选择采用哪种捕捉函数

sa_mask :
在执行捕捉函数时,设置阻塞其它信号,sa_mask|
进程阻塞信号集,退出捕捉函数后,还原回原有的阻塞信号集

sa_flags : SA_SIGINFO
或者0

sa_restorer:保留,已过时。

案例说明:

#include<stdio.h>

#include<signal.h>

#include<unistd.h>

 

void do_sig(int num)

{

    int n = 5;

    printf("I am do_sig\n");

    printf("num = %d\n",num);

    while(n--)

    {

  
      printf("num = %d\n",num);

        sleep(1);

    }

}

 

int main(void)

{

    struct sigaction act;

    act.sa_handler = do_sig;

    //act.sa_handler = SIG_DFL;

    //act.sa_handler = SIG_IGN;

    sigemptyset(&act.sa_mask);

    sigaddset(&act.sa_mask,SIGQUIT);

    act.sa_flags = 0;

 

    sigaction(SIGINT,&act,NULL);

 

   
 while(1)

    {

        printf("**********\n");

      
sleep(1);

    }

    return 0;

}

9 C标准库信号处理函数

typedef void (*sighandler_t)(int)

sighandler_t signal(int signum,sighandler_t handler)

int system(const char *command)

system的本质是:集合fork,exec,wait一体

10
可重入函数

A:不含全局变量和静态变量是可重入函数的一个要素

B:可重入函数man 
7  signal

C:在信号捕捉函数里应可重入函数

例如:strtok就是一个不可重入函数,因为strtok内部维护了一个内部静态指针,保存上一次切割到的位置,如果信号的捕捉函数中也去调用strtok函数,则会造成切割字符串混乱,应用strtok_r版本,r表示可重入。

11时序竞态

int pause(void)

使调用进程挂起,直到有信号递达,如果递达信号是忽略,则继续挂起

int sigsuspend(const sigset_t *mask)

以通过指定mask来临时解除对某个信号的屏蔽,然后挂起等待,当sigsuspend返回时,进程的信号屏蔽字恢复为原来的值

#include <unistd.h>

#include <signal.h>

#include <stdio.h>

void sig_alrm(int signo)

{

/* nothing to do */

}

unsigned int mysleep(unsigned int nsecs)

{

struct sigaction newact, oldact;

unsigned int unslept;

newact.sa_handler = sig_alrm;

sigemptyset(&newact.sa_mask);

newact.sa_flags = 0;

sigaction(SIGALRM, &newact, &oldact);

 

alarm(nsecs);

//在alarm的时候,可能会转到其它程序,这之后永远都执行不到下面的这行,因为信号已经执行过了

pause();

 

unslept = alarm(0);

sigaction(SIGALRM, &oldact, NULL);

return unslept;

}

 

int main(void)

{

while(1){

mysleep(2);

printf("Two seconds passed\n");

}

return 0;

}

mysleep的改进版

#include<unistd.h>

#include<signal.h>

#include<stdio.h>

 

void sig_alrm(int signo)

{  

    /* nothing to do*/

}

 

unsigned int mysleep(unsigned int nsecs) {  

struct sigaction newact,oldact;

   
sigset_tnewmask,oldmask,suspmask;

   
unsigned int unslept;

   
/*set our handler,saveprevious information*/

   
newact.sa_handler =sig_alrm;

 
  sigemptyset(&newact.sa_mask);

   
newact.sa_flags = 0;

   sigaction(SIGALRM,&newact,&oldact);

   
/*block SIGALRM and savecurrent signal mask*/

   
sigemptyset(&newmask);

 sigaddset(&newmask,SIGALRM);

 sigprocmask(SIG_BLOCK,&newmask,&oldmask);

  
   alarm(nsecs);

   suspmask = oldmask;

 
/*make sure SIGALRM isn'tblocked*/

   sigdelset(&suspmask,SIGALRM);

 
sigsuspend(&suspmask);/*waitfor any signal to be caught*/

   
/*some signal has bencaught,SIGALRM is now blocked*/

  unslept = alarm(0);

  
   sigaction(SIGALRM,&oldact,NULL);/*resetprevious action*/

   
/*reset signal mask,whichunblocks SIGALRM*/

   sigprocmask(SIG_SETMASK,&oldmask,NULL);

   return(unslept);

}

 

int main(void) {

while(1)

   
{

    
    sleep(2);

  
printf("Two secondspassed\n");

 
    }

 
return 0;

}

时间: 2024-07-30 10:24:13

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

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

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

什么是可重入函数

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

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

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

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 inte

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

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

Linux多线程可重入函数

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

linux可重入、异步信号安全和线程安全

一 可重入函数 当一个被捕获的信号被一个进程处理时,进程执行的普通的指令序列会被一个信号处理器暂时地中断.它首先执行该信号处理程序中的指令.如果从信号处理程序返回(例如没有调用exit或longjmp),则继续执行在捕获到信号时进程正在执行的正常指令序列(这和当一个硬件中断发生是所发生的事情相似.)但是在信号处理器里,我们并不知道当信号被捕获时进程正在执行哪里的代码. 如果进程正使用malloc在它的堆上分配额外的内存,而此时由于捕捉到信号而插入执行该信号处理程序,其中又调用了malloc,这会

深入理解可重入与线程安全

在多线程编程和信号处理过程中,经常会遇到可重入(reentrance)与线程安全(thread-safe). 很多人纠结于reentrance和thread-safe两个概念理解纠缠不清.我想救我对reentrance和thread-safe的理解作个总结   一.可重入(reentrance) 首先来看下APUE中,列出的可重入函数:   accept fchmod lseek sendto stat access fchown lstat setgid symlink aio_error f

可重入和不可重入【转】

转自:http://blog.csdn.net/wenhui_/article/details/6889013重入一般可以理解为一个函数在同时多次调用,例如操作系统在进程调度过程中,或者单片机.处理器等的中断的时候会发生重入的现象. 一般浮点运算都是由专门的硬件来完成,举个例子假设有个硬件寄存器名字叫做FLOAT,用来计算和存放浮点数的中间运算结果 假设有这么个函数 void fun() { //...这个函数对FLOAT寄存器进行操作 } 假如第一次执行,有个对浮点数操作运算的结果临时存在FL