android开发实战 leetcodeLCP excel iis oauth get icons Amaze UI Select2 郑州网站建设 jquery点击事件 jquery查找子元素 oracle添加索引 office配置进度 matlab不等于怎么表示 mac版的matlab好用吗 python的random函数 python命令 python字符串匹配 java语言学习 java编程入门 java连数据库 java的数据类型 java字符串查找 java方法的重载 java开发入门 java连接sql ie模拟器 acmecadconverter win10长期服务版 两表关联查询 din字体下载 凯恩与林奇2下载 程序卸载 js转数字 ps调整边缘抠头发丝 0x000008e sqlprompt jquery手册 光标变粗
当前位置: 首页 > 学习教程  > 编程语言

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

2021/1/28 22:38:58 文章标签:

Linux 信号(signal) 信号 信号的原理 对于 Linux来说,实际信号是软中断,可参考:点个外卖,我把「软中断」搞懂了,许多重要的程序都需要处理信号。 信号,为 Linux 提供了一种处理异…

Linux 信号(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已经对进程不起作用了,这两个信号被进程忽略。
在这里插入图片描述


本文链接: http://www.dtmao.cc/news_show_650038.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?