博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
21-关于linux信号的基本使用
阅读量:2042 次
发布时间:2019-04-28

本文共 3696 字,大约阅读时间需要 12 分钟。

1. 什么是信号

  简而言之,信号是事件发生时用于给进程发送各种通知的机制,以便通知进程发生何种事件。

  站在操作系统的角度来说,信号也称为软件中断,因为信号可以改变程序的执行流程,大多数情况下无法预测信号到达的精确时间。当信号传递给进程时,它会中断进程当前正在进行的任何操作,并强制进程处理或忽略信号,又或者在某些情况下终止进程。

2. 向进程发送信号

  比如写一个A程序每隔1秒打印一次hello world,然后在终端按Ctrl + C时,系统就会产生一个SIGINT信号并发送给A程序,我们无法预测SIGINT信号何时到达A程序,但是当A程序收到SIGINT信号时,无论A程序此时执行到哪里了,SIGINT信号都会中断A程序的执行流程,同时强制A程序处理SIGINT信号,由于SIGINT信号的默认处理动作是终止一个进程,那么A程序会立即终止结束,而不是按正常的执行流程终止结束。

3. 产生信号相关的事件

  虽然信号是进程间通信(IPC)的一种方式,进程也可以向自身发送信号,但是通常是由内核来产生信号的,一般产生信号的事件大概有以下几种:

  1 . 按键产生,如Ctrl+c,Ctrl+z,Ctrl+\等

  2 . 系统调用产生,如kill、raise、abort等系统调用函数,在程序中通过调用某些系统函数给进程发送信号

  3 . 硬件异常产生,如非法访问内存(段错误)、除0(浮点数例外)、内存对齐出错(总线错误)

  4 . 在终端上输入命令产生信号,如kill命令

  拿按键产生信号来说,比如想要终止一个进程就可以通过按键Ctrl+c的方式使系统内核产生一个信号并发送给这个进程,而这个进程接收到这个信号并执行这个信号的默认处理动作:终止一个进程。

  Ctrl+\也是终止一个进程,区别在于Ctrl+c是发送信号终止进程的执行,相当于直接把进程干掉,而Ctrl+\是发送信号让进程尽快的结束运行,没有那么直接。
  Ctrl+z会向正在运行的进程发送SIGTSTP信号,默认情况下,此信号会导致进程暂停执行。

4. linux支持的信号

  有同学可能会问,linux系统中到底有多少信号呢?如果我们想要查看当前系统支持的信号可以使用kill –l命令查看当前系统可使用的信号:

在这里插入图片描述

  linux中的信号的编号是从1开始的,其中编号是1 - 31的称之为常规信号(也叫普通信号或标准信号),34-64号称之为实时信号,驱动编程与硬件相关。另外32和33编号的信号作为保留并未使用,不同的linux系统有些信号可能会不太一样,如果你想要详细了解关于信号更多的资料可以参考《linux/unix系统编程手册(上册)》,这本书对于信号的介绍非常详细。

5 . 使用系统调用kill发送信号

  前面我们讲过shell命令也可以产生信号,比如kill命令,而kill函数实现一样的功能,给指定进程发送指定信号。

函数原型:

int kill(pid_t pid, int sig);

返回值:成功0;失败-1并设置errno

参数sig:

  指定要发送的信号,如果sig为0,通常用来测试是否有权限(权限保护)向进程发信号。

参数pid:

  pid > 0表示发送信号给pid指定的进程。

  pid = 0表示发送信号给与调用kill函数的进程属于同一进程组的所有进程

  pid < -1表示取|pid|发给对应进程组

  pid = -1表示向系统中所有进程发送信号,前提是有权限

6. 实验

循环创建5个子进程,任一子进程用kill函数终止其父进程

#include 
#include
#include
#include
#define N 5int main(void) {
int i; //默认创建5个子进程 for(i = 0; i < N; i++){
if(fork() == 0){
break; } } if (i == 3) {
sleep(1); printf("-----------child ---pid = %d, ppid = %d\n", getpid(), getppid()); //子进程终止父进程 kill(getppid(), SIGKILL); //父进程 } else if (i == N) {
printf("I am parent, pid = %d\n", getpid()); while(1); } return 0;}

程序执行结果:

在这里插入图片描述

7. raise函数的用法

  raise 函数是给当前进程发送指定信号(自己给自己发),注意raise函数和kill函数的区别。

  当进程调用raise函数向自身发送信号时,信号将会立即递送,即在raise返回前。另外raise出错不一定返回-1,调用raise唯一的错误就是EINVAL,即参数isg无效。

函数原型:

int raise(int sig); 成功:0,失败非0值
代码实验:
#include 
#include
#include
#include
#include
int main(void){
int ret; while(1){
sleep(1); //打印进程id printf("pid = %d\n", getpid()); ret = raise(SIGINT); //失败直接break if(ret != 0){
break; } } return 0;}

程序执行结果:

在这里插入图片描述

8. 信号的处理方式

信号的处理方式一般有以下几种:

  1. 执行默认动作,对于大多数信号的系统默认动作是终止该进程。

  2. 忽略(丢弃),大多数信号都可使用这种方式来处理

  3. 捕捉(调用自定义信号处理函数)

9. 信号捕捉函数——signal

  根据信号的处理方式可知,如果我们不想信号执行默认的处理动作时,就要进行捕捉信号,并注册自定义信号处理函数,而signal函数就是用来做这件事的。

  需要注意的是,signal函数由ANSI定义,由于历史原因在不同版本的Unix实现中可能存在着差异,这意味着如果程序需要考虑可移植性的话,那么应该尽量避免使用它,取而代之使用sigaction函数。

函数原型:

#include 
typedef void (*sighandler_t)(int);sighandler_t signal(int signum, sighandler_t handler);

参数signum:表示要捕捉的信号

参数handler:捕捉后默认处理动作函数指针

另外系统还为handler参数提供了两个宏,分别是 SIG_DFL和 SIG_IGN :

  1. 如果handler指定为SIG_DFL,系统将为该信号指定默认的信号处理函数。

  2. 如果 handler指定为SIG_IGN,系统将忽略该信号即内核会将信号丢弃,而进程不会知道曾经产生了该信号。

返回值说明:

   成功返回函数指针,即先前的信号处理函数,也有可能是SIG_DFL或SIG_IGN;失败则返回SIG_ERR说明注册失败,设置errno

signal函数实现捕捉信号实验:

#include 
#include
#include
#include
#include
void do_sig(int a){
printf("hello, SIGINT\n");}int main(void){
if (signal(SIGINT, do_sig) == SIG_ERR) {
perror("signal"); exit(1); } while (1) {
printf("---------------------\n"); sleep(1); } return 0;}

程序执行结果:

在这里插入图片描述

   当使用signal函数捕捉了SIGINT信号后,此时在终端输入Ctrl-C发送SIGINT信号不再是让进程退出了,而是调用注册的信号处理函数,打印hello SIGINT。

你可能感兴趣的文章
Leetcode C++ 《第200场周赛》
查看>>
Leetcode C++ 《第201场周赛》
查看>>
云原生 第十章 应用存储和持久化数据卷:存储快照和拓扑调度
查看>>
云原生 第十一章 应用健康
查看>>
Leetcode C++ 《第202场周赛》
查看>>
云原生 第十二章 可观测性:监控与日志
查看>>
Leetcode C++ 《第203场周赛》
查看>>
云原生 第十三章 Kubernetes网络概念及策略控制
查看>>
《redis设计与实现》 第一部分:数据结构与对象 || 读书笔记
查看>>
《redis设计与实现》 第二部分(第9-11章):单机数据库的实现
查看>>
算法工程师 面经2019年5月
查看>>
搜索架构师 一面面经2019年6月
查看>>
稻草人手记
查看>>
第一次kaggle比赛 回顾篇
查看>>
leetcode 50. Pow(x, n)
查看>>
leetcode 130. Surrounded Regions
查看>>
【托业】【全真题库】TEST2-语法题
查看>>
博客文格式优化
查看>>
【托业】【新托业全真模拟】疑难语法题知识点总结(01~05)
查看>>
【SQL】group by 和order by 的区别。
查看>>