进程篇——信号

信号是什么?  

     信号其实就是传递的一种信息,让我们能根据这个信息进一步的去处理响应的事件。比如说:红绿灯,绿灯亮了,这就是一个信号,提醒我们此时可以安全的过马路了。比如我们键盘按下:Ctrl-C 给前台进程发送信号,终止进程。

    对于信号的理解,我们可以类比现实生活,举个例子:老师给我们布置了一个作业,然后我们将作业记录下来是什么,然后需要一段时间去完成作业,最后上交给老师。linux下信号同样如此,需要产生一个信号,然后在一个适合的时间,进程去进行处理。

  1. 信号实质是软中断,用于通知进程发生某些事件。
  2. 信号作用:通知事件的发生,信号产生之后第一时间也不是直接处理,而是先存储下来。再处理信号
  3. 信号生命周期:信号的产生—>信号的注册—>信号的堵塞—>信号的注销—>信号的处理

信号是系统预先定义好的某些特定的事件,信号可以被产生,可以被接收,产生和接收的主体都是进程。进程收到信号之后,会有三种响应方式:忽略、默认、自定义(捕获)

        1.忽略此信号。

        2.执行该信号的默认处理动作(终止该信号)

        3.提供一个信号处理函数(自定义动作),要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式被称为 捕捉(catch)一个信号。

 

产生信号的方式

  (1)通过终端按键(组合键)产生信号

  用户在终端按下某些键时,终端驱动程序会发送信号给前台进程,例如Ctrl-C 产生SIGINT信号,Ctrl-\ 产生SIGOUIT信号等

       概念:当一个进程要异常终止时,可以选择把进程的用户空间内存数据全部保存到磁盘上,文件名通常是core,这叫做core Dump,也叫 核心转储,帮助开发者进行调试,在程序崩溃时把内存数据dump到磁盘上,让gdb 识别。

 (2)硬件异常产生的信号

     硬件异常产生信号,这些条件由硬件检测到并通知内核,然后内核向当前进程发送适当的信号。 例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释为 SIGFPE信号发送给进程。 再比如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV 信号发送给进程。

 (3)调用系统函数向进程发信号

        1. 一个进程可以调用 kill(2)函数 发送信号给另一个进程。可以用kill(1)命令发送信号给某个进程,kill(1)命令也是调用kill(2)函数实现的,如果不明确指定信号则发送给 SIGTREM信号,该信号的默认处理动作是终止进程。

        2.raise函数可以给当前进程发送信号,相当于自己给自己发信号。

#include<signal.h>
int kill(pid_t pid, int signal);
int raise(int signal);
//都是成功返回0,失败返回-1;

     3. absort函数可以使当前进程接收到信号而异常终止

#include<stdlib.h>
void absort(void);
//没有返回值,总能调用成功;

 (4)由软件条件产生信号

       1.SIGPIPE 是一种软件条件产生的信号。在匿名管道中,如果读端的文件描述符关闭了,那么写端就会发送SIGPIPE来 导致write进程终止退出。

       2.alarm函数可以设置一个闹钟,在seconds 之后给当前进程发送一个SIGALARM信号,该信号的默认处理时结束当前进程。

#include<unistd.h>

unsigned int alarm(unsigned int seconds);
//返回值是0或者返回值是当前second余下的秒数;
//函数的返回值仍是以前闹钟设置的余下秒数

Signal()函数可以修改信号的响应方式:

Typedef  void (*sighandle_t)(int);

Sighandle_t (*signal,sighandle_t);

忽略:  SIG_IGN

默认:  SIG_DFL

自定义:  自己写的信号处理函数

 

Kill函数可以向指定的进程发送指定的信号:

int  kill(pid_t  pid ,  int  signo);

Pid > 0   指定将信号发送给那个进程

Pid==0   信号被发送到和当前进程在同一个进程组的进程

Pid == -1  将信号发送给系统上有权限发送的所有的进程

Pid < -1   将信号发送给进程组id等于pid 绝对值,并且有权限发送的所有的进程。

Sig      指定发送信号的类型

Raise函数将信号发送给自己:

 Int  raise(int sig);

 相当于:  kill(getpid,sig);

 

信号集

   在实际的应用中一个应用层程序需要对多个信号进行处理,为了方便,linux系统引进了信号集概念。信号集用多个信号组成的数据类型sigset_t。可用以下的系统调用设置信号集中国所包含的数据。

   Int  sigemptyset(sigset_t  *set);  将set集合置空,成功则返回0,失败则返回-1.

   Int  sigaddset(sigset_t *set, int signo)将signal信号加入到 set集合,成功则返回0,失败则返回-1.

   Int  sigdelset(sigset_t*set,int signo);  从set集合中移除signo信号,成功则返回0,失败则返回-1.

   Int  sigismember(const sigset_t  *set , int signo );  signo 判断信号是否存在于set集合中,若真返回1,假返回0,失败返回-1.

   Int sigprocmask(int how, const  sigset_t  *set,sigset_t *oset);  用于检测或更改其信号屏蔽字,包含头文件<signal.h>  ,成功则返回0,失败则返回1.

参数:how 指示如何修改屏蔽信号

   Set 是一个非空指针时,根据how修改屏蔽信号。

Oset是一个 非空指针时,存放当前屏蔽信号集

若set为NULL ,不改变该进程的信号屏蔽字,how也意义。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值