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



1信号产生原因

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的信号集

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

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

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

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

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

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

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

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

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

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

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

为阻塞而不是忽略。

5sigprocmask

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

依赖的头文件:

#include

函数声明:

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

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

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

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

    how参数的含义

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

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

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

6sigpending(未决打印信号)

#include

int sigpending(sigset_t *set)

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

返回-1

6案例说明:

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

运行结果:

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

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

这时按Ctrl+\结束。

7信号捕捉设定

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

8.sigaction

#include

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

#include

#include

 

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的本质是:集合forkexecwait一体

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

#include

#include

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

#include

#include

 

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;

}

你可能感兴趣的:(#,Linux,系统编程)