当前位置:   article > 正文

信号的捕捉及使用_信号捕捉

信号捕捉

title: 信号的捕捉及使用
date: 2019-08-05 09:01:44
tags: Linux
categories: Linux

       

1、信号的安装

        如果进程要处理某一信号,那么就要在进程中安装该信号。安装信号作用是确定进程针对该信号值的动作之间的映射关系,即进程将要处理哪个信号;该信号被传递给进程时,将执行何种操作。

2、信号的捕捉

函数原型#include <signal.h>
sighandler_t signal(int signum, sighandler_t handler);
typedef void (*sighandler_t)(int);
参数signum:要捕捉的信号
handler:信号处理函数
信号处理函数中的int参数为传递的信号

案列1:

在这里插入图片描述

进程在运行过程中如果没有信号产生,会执行默认的程序,如果产生信号,会跳转到signal 信号处理函数当中执行信号的动作 ,执行完毕,返回主程序继续执行 。 信号默认动作是终止进程比如ctrl c 如果 捕捉信号成功,则 不会执行默认的动作 。

案列2:

        在前面的《信号基础介绍》第七小节介绍了,信号的处理有三种方式:①、执行默认动作 ;②、忽略该信号;③、执行用户期望的动作(上诉案列1就是)。这个案列我们做个信号产生时忽略该信号的实验。

在这里插入图片描述

案列3:

①、一个进程中接受多个相同类型的信号

        当同一个进程当中有多个相同信号,信号发生时会执行完第一个信号之后,再执行第二个信号。但不可靠信号不支持排队 ,不会将所有的信号全部捕捉 。(例如:你在主函数中只写了两个捕捉信号函数,捕捉的是同一个信号,那么当连续发生该信号二次以上时,只会执行两次信号的处理函数)

②、一个进程中接受多个不同类型的信号

        同一个进程当中产生多个不同类型的信号,当第一个信号在执行信号处理函数,第二个不同类型的信号发生,会优先执行第二个信号,执行完毕,再接着继续未执行完毕的第一个信号。类似与中断嵌套。

案列3:信号和文件的结合

如果当调用文件IO 来读取一个文件的内容,在读取过程中如果发生一个信号,执行完毕信号处理函数,在unix 当中是继续之前没有读完的读操作,在LinuxPOSIX 是重新开始读操作

3、kill信号发送

函数原型int kill(pid_t pid, int sig);
功能向进程号为pid中发生信号值为sig的信号
参数pid : 指定的进程号
pid > 0 sig发送给ID为pid的进程
pid== 0 sig发送给与发送进程同组的所有进程
pid<0 sig发送给组ID为|-pid|的进程,并且发送进程具有向其发送信号的权限
pid== -1 sig发送给发送进程有权限向他们发送信号的系统上的所有进程
sig : 要发送的信号
返回值成功: 0
失败:-1

4、Raise信号发送

与 kill 函数一样,raise 函数也是用来发送信号给进程的,但是它只能发送信号给当前进程,自己给自己发送信号。不能发送给其他进程。

函数原型int raise(int sig);
功能给当前进程发送信号
参数sig :要发送的信号

5、进程的挂起pause

        #include <unistd.h>
        int pause(void);
        功能: 挂起进程

        经常 alarm连用定时器会定时时间到之后会结束挂起状态 。

6、闹钟函数alarm

        #include <unistd.h>

        unsigned int alarm(unsigned int seconds);

        功能; 调用此函数会触发 ALARM 信号 定时器

        参数:

                        seconds : 定时时间 单位秒

7、sigaction信号安装函数

        Sigaction 是新版本内核中出现的函数,在Linux系统中,signal就是使用这个函数实现的。它有三个参数,支持信号传递信息,主要用来与sigqueue()系统调用配合使用,当然,sigaction()同样支持非实时信号的安装。Sigaction()优于signal 主要体现在支持信号带有参数。这两个函数的最大区别在于经过sigaction安装的信号都能传递信息给信号处理函数,而经过signal安装的信号不能向信号处理函数传递信息。.

函数原型int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
函数功能注册信号处理函数 信号的安装
参数signum :需要捕捉的信号
Act: 里面包含信号处理函数地址,处理方式等信息。
Oldact: 输出参数,函数调用成功后oldact里面保存以前对signum的处理方式的信息,通常为NULL
返回值成功:0
失败:-1

参数2结构体

 struct sigaction 
 {
    void     (*sa_handler)(int );                             //旧类型的信号处理函数指针
    void     (*sa_sigaction)(int  , siginfo_t *  , void *  );  //新类型的信号处理函数指针
    sigset_t sa_mask;                                          //信号被阻塞的信号集合
    int      sa_flags;                                  //信号处理方式掩码(SA_SIGINFO)
    void     (*sa_restorer)(void);    //保留,不要使用
    
 };

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

成员说明:

①、sa_handler 是一个函数指针,旧类型信号处理函数,用于指向原型为void handler(int)的信号处理函数地址,如果用这个成员,则将sa_flags= 0,就等同于signal()函数。

②、sa_sigaction 也是一个函数指针,新类型的信号处理函数用于指向原型为:

void handler(int iSignNum,siginfo_t * pSignInfo,void * pReserved) ;的信号处理函数

函数原型void handler(int iSignNum,siginfo_t * pSignInfo,void * pReserved)
函数功能信号处理函数,接受到该信号你做什么
参数iSignNum:传入的信号
pSignInfo:与该信号相关的一些信息,它是个结构体,定义如下
pReserved:保留,现在没用,通常为NULL
typedef struct siginfo_t {
		int si_signo;    //信号编号
		int si_errno;    //如果为非零值则错误代码与之关联
        int si_code;    //说明进程如何接收信号以及何处收到
        pid_t si_pid;    //适用于SIGCHLD ,代表被终止进程的PID
        pid_t si_uid;     //适用于SIGCHLD,代表被终止进程所拥有的进程的UID
        int si_status;     //适用于SIGHLD,代表被终止进程的状态
        clock_t si_utime;   //适用于SIGHLD,代表被终止进程所消耗的用户时间
        clock_t si_stime    //适用于SIGHLD,代表被终止进程所消耗系统的时间
        sigval_t si_value;    //存放sigqueue函数传递的额外信息给处理函数
        int si_int;       //存放sigqueue函数传递的额外信息给处理函数
        void *si_ptr;    //存放sigqueue 函数传递的额外信息给处理函数
        void *si_addr;   
        int si_band;
        int si_fd;
};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

③、 sa_handler和sa_sigaction 只应该有一个生效。

        如果想采用老的信号处理机制,让sa_handeler指向正确的信号处理函数,并且让字段sa_flags为0;

        如果想采用新的信号处理机制,让sa_sigaction 指向正确的信号处理函数,并且让字段sa_flags包含SA_SIGINFO选项。

④、 sa_mask是一个包含信号集合的结构体,该结构体内的信号表示在进行信号处理时,将要被阻塞的信号。需要注意的是,当在执行当前的信号处理程序时,后面再来的信号如果和当前信号相同,同样会被阻塞。

针对sigset_t结构体,有一组专门的函数对它进行处理,它们是:

int sigemptyset(sigset_t * set)清空信号集合 set
int sigfillset(sigset_t * set)将所有信号填充进 set中
int sigaddset(sigset_t * set, int signum)往 set 中添加信号 signum
int sigdelset(sigset_t * set, int signum)从 set中移除信号 signum
int sigismember(const sigset_t * set, int signum)判断 signnum 是不是包含在 set 中
int sigpending(sigset_t * set)将被阻塞的信号集合由参数 set指针返回

⑤、 sa_flags字段是一组掩码的合成值,指示信号处理时所应该采取的一些行为

各掩码的含义如表5.1所示:

掩码描述
SA_RESETHAND 处理完毕要捕捉的信号后,将自动撤消信号处理函数的注册,即必须再重新注册信号处理函数,才能继续处理接下来产生的信号。该选项不符合一般的信号处理流程,现已经被废弃。
SA_NODEFER在处理信号时,如果又发生了其它的信号,则立即进入其它信号的处理,等其它信号处理完毕后,再继续处理当前的信号,即递规地处理。
SA_RESTART 如果在发生信号时,程序正阻塞在某个系统调用,例如调用 read()函数,则在处理完毕信号后,接着从阻塞的系统返回。如果不指定该参数,中断处理完毕之后, read 函数读取失败。
SA_SIGINFO 指示结构体的信号处理函数指针是哪个有效,如果 sa_flags 包含该掩码,则 sa_sigaction 指针有效,否则是 sa_handler 指针有效。(常用)

旧版信号处理实例:

在这里插入图片描述

新版信号处理实例:
在这里插入图片描述

8、sigqueue向信号处理函数中传递信息需要

函数原型int sigqueue(pid_t pid, int sig, const union sigval value);
功能发送信号,并且可以在信号上面附加信息
参数pid:向哪个进程发送
sig:发送的信号
union sigval valueunion sigval{
int sival_int; //可以传递int 类型的数据
void *sival_ptr; // 其他类型的数据
};

实例:

利用两个陌生进程传递信号,实现通信。(接收到信号以外的数据就算通信成功

在这里插入图片描述

实验现象:
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/460196
推荐阅读
相关标签
  

闽ICP备14008679号