Liunx系统编程篇—进程通信(五)信号(一)(原理、概述、创建、实战)(kill、signal)

信号

信号的原理

对于 Linux来说,实际信号是软中断,可参考:点个外卖,我把「软中断」搞懂了,许多重要的程序都需要处理信号。
信号,为 Linux 提供了一种处理异步事件的方法。比如,终端用户输入了ctrl+c来中断程序,会通过信号机制停止一个程序。

信号概述

1、信号的名字和编号:

每个信号都有一个名字和编号,这些名字都以“SIG”开头,例如“SIGIO ”、“SIGCHLD”等等。
信号定义在signal.h头文件中,信号名都定义为正整数。
具体的信号名称可以 使用kill -l来查看信号 的名字以及序号,
信号是 从1开始编号的,不存在0号信号。kill对于信号0又特殊的应用。
在这里插入图片描述

2、信号的处理:

信号的处理有三种方法,分别是:忽略、捕捉和默认动作

忽略信号

大多数信号可以使用这个方式来处理,但是有两种信号不能被忽略(分别是 SIGKILL和SIGSTOP)。因为他们向内核和超级用户提供了进程终止和停止的可靠方法,如果忽略了,那么这个进程就变成了没人能管理的的进程,显然是内核设计者不希望看到的场景。
==SIG_IGN为系统自带的宏函数。==例:

 signal(SIGINT,SIG_IGN);//将SIGINT信号(ctrl+C、2)忽略
捕捉信号

需要告诉内核,用户希望如何处理某一种信号,说白了就是写一个信号处理函数,然后将这个函数告诉内核。当该信号产生时,由内核来调用用户自定义的函数,以此来实现某种信号的处理。

系统默认动作

对于每个信号来说,系统都对应由默认的处理动作,当发生了该信号,系统会自动执行。不过,对系统来说,大部分的处理方式都比较粗暴,就是直接杀死该进程。
具体的信号默认动作可以使用man 7 signal来查看系统的具体定义。在此,我就不详细展开了,需要查看的,可以自行查看。也可以参考 《UNIX 环境高级编程(第三部)》的 P251——P256中间对于每个信号有详细的说明。
了解了信号的概述,那么,信号是如何来使用呢?

其实对于常用的 kill 命令就是一个发送信号的工具,kill 9 PID来杀死进程。比如,我在后台运行了一个 top 工具,通过 ps 命令可以查看他的 PID,通过 kill 9 来发送了一个终止进程的信号来结束了 top 进程。如果查看信号编号和名称,可以发现9对应的是 9) SIGKILL,正是杀死该进程的信号。而以下的执行过程实际也就是执行了9号信号的默认动作——杀死进程。

kill -9 进程PID
kill -SIGKILL 进程PID

这两句实现功能一样。
在这里插入图片描述
在这里插入图片描述
对于信号来说,最大的意义不是为了杀死信号,而是实现一些异步通讯的手段,那么如何来自定义信号的处理函数呢?

创建

常用API
信号处理函数的注册

入门版:函数signal
高级版:函数sigaction

信号处理发送函数

1.入门版:kill
2.高级版:sigqueue

在正式开始了解这两个函数之前,可以先来思考一下,处理中断都需要处理什么问题。

按照我们之前思路来看,可以发送的信号类型是多种多样的,每种信号的处理可能不一定相同,那么,我们肯定需要知道到底发生了什么信号。
另外,虽然我们知道了系统发出来的是哪种信号,但是还有一点也很重要,就是系统产生了一个信号,是由谁来响应?
如果系统通过 ctrl+c 产生了一个 SIGINT(中断信号),显然不是所有程序同时结束,那么,信号一定需要有一个接收者。对于处理信号的程序来说,接收者就是自己。

signal函数

signal 的函数原型

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

函数原型由两部分组成,一个是真实处理信号的函数,另一个是注册函数了。
注册函数:
sighandler_t signal(int signum, sighandler_t handler);函数来说,
signum :信号的编号。
handler :中断函数的指针。

handler函数

真实处理信号的函数:
typedef void (*sighandler_t)(int);中断函数的原型中,有一个参数是 int 类型,显然也是信号产生的类型,方便使用一个函数来处理多个信号。
我们先来看看简单一个信号注册的代码示例吧。

实例1:信号的处理:捕捉动作

domo1.c

信号处理函数的注册

#include<stdio.h>
#include <signal.h>
//真实处理信号的函数
void handler(int signum)
{
        printf("get signum=%d\n",signum);
        switch(signum){
                case 2:
                        printf("SIGINT\n");
                        break;
                case 10:
                        printf("SIGUSR1\n");
                        break;
        }
}
int main()
{
        signal(SIGINT,handler);//信号处理函数的注册
        signal(SIGUSR1,handler);//信号处理函数的注册
        while(1);
        return 0;
}
domo2.c

demo2主要是将kill信号处理发送函数置于程序中,同时也可以使用system来实现kill。
信号处理发送函数:

#include<stdio.h>
#include <signal.h>
#include <sys/types.h>
int main(int argc,char **argv)
{
        int signum=0;
        int pid=0;
        char cmd[128]={0};//设置system函数处理命令的大小
        signum= atoi(argv[1]);//转为整型
        pid= atoi(argv[2]);//转为整型
        printf("num=%d\n",signum);
        printf("pid=%d\n",pid);
       	
		kill(pid,signum);
		// sprintf(cmd,"kill -%d %d",signum,pid);
        // system(cmd);
        printf("send signal ok\n");
        return 0;
}

注:
1、atoi (表示 ascii to integer)是把字符串转换成整型数的一个函数。
2、sprintf指的是字符串格式化命令,
函数声明为 int sprintf(char *string, char *format [,argument,…]);,
主要功能是把格式化的数据写入某个字符串中,即发送格式化输出到 string 所指向的字符串。
3、

printf(cmd,"kill -%d %d",signum,pid);
system(cmd);

也可以实现kill(pid,signum);的功能

实验结果:
domo1实现:

在这里插入图片描述
在这里插入图片描述

domo2实现:

demo2主要是将kill信号处理发送函数置于程序中,同时也可以使用system来实现kill。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实例2:信号的处理:忽略

#include<stdio.h>
#include <signal.h>
void handler(int signum)
{
        printf("get signum=%d\n",signum);
        switch(signum){
                case 2:
                        printf("SIGINT\n");
                        break;
                case 10:
                        printf("SIGUSR1\n");
                        break;
        }

}
int main()
{
        signal(SIGINT,SIG_IGN);//将SIGINT信号(ctrl+C、2)忽略
        signal(SIGUSR1,SIG_IGN);//将SIGUSR1信号(10)忽略

        while(1);


        return 0;
}

注:SIG_IGN:为系统自带的宏

实验结果:

会发现ctrl+c与kill -10 pid已经对进程不起作用了,这两个信号被进程忽略。
在这里插入图片描述

参考文献

Linux 信号(signal)
点个外卖,我把「软中断」搞懂了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值