欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Linux进程信号之如何产生信号

程序员文章站 2022-07-12 10:29:39
...

一、信号概念

在日常生活中,我们经常也会遇见信号,比如“上下课的铃声”、“十字路口的红路灯” 。而在Linux中,信号如同交通信号灯一样,它就是给操作系统或者进程提供某种信息,让操作系统或者进程做出某种对应的反应,就如同十字路口的红路灯显示红灯时,告诉行人此时应该停下……

让我们来看一下Linux系统定义的信号:
Linux进程信号之如何产生信号
如上图所示,一共有62种信号(是不是有读者和我刚开始时一样以为有64种,哈哈哈!上当了吧!)。其中1~31为普通信号,34~64为实时信号。
每个信号都有一个编号和宏定义名称,这些宏定义可以在signal.h中找到。这些信号各自在什么条件下产生,默认的处理动作是什么,在signal(7)中都有详细说明:通过man 7 signal命令可前往查看。
Linux进程信号之如何产生信号
二、信号产生
信号有以下四种产生方式:

* (1)在终端按下某种按键,终端驱动程序会发送信号给前台进程(eg:Ctrl+C产生SIGINT信号)
* (2)硬件异常产生信号,这些条件由硬件检测到并通知内核,然后内核向当前进程发送适当的信号
* (3)通过系统函数向进程发信号(闹钟超时产生SIGALRM信号;想读端已经关闭的管道写入数据时产生SIGPIPE信号)
* (4)软件条件产生

信号处理可选的处理动作有以下三种:

* (1)忽略此信号
* (2)执行该信号的默认处理动作
* (3)提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式称为捕捉(Catch)一个信号

注:9号信号SIGKILL不能被捕捉


1. 产生方式一:通过终端按键产生信号

我们先来写一个死循环的小程序:(如下图所示)
Linux进程信号之如何产生信号
Linux进程信号之如何产生信号
运行结果:
Linux进程信号之如何产生信号
运行之,发现去掉信号捕捉,键入Ctrl+\ 就会发现后边多了一个core dumped
因为ctrl+C对应的是SIGINT信号,它的默认处理动作是终止进程;ctrl+\ 对应的是SIGQUIT信号,它的默认处理动作是终止进程并且Core Dump。

* Core  Dump(核心转储)

什么是Core Dump嘞? 当一个进程异常终止时,可以选择把进程的用户空间内存数据全部保存到磁盘上,文件名通常是core,这叫做Core Dump。core文件可以帮助开发者进行调试,在程序崩溃之时把内存数据dump到硬盘上,让gdb识别。可以事后调试

一般情况下,系统默认情况下是不允许生成core文件,因为对于线上服务而言,出core的过程意味着服务暂时不能正常响应,需要恢复,并且随着吐core进程的内存空间越大,这个过程就会持续很长一段时间,并且会很占内存(每重启一次进程就会有一个core文件)。同时core文件可能包含用户的密码等敏感信息,不太安全

在开发调试阶段可以用ulimit命令改变这个限制,允许产生core文件。

ulimit -c 1024   // 用ulimit命令改变shell进程的Resource Limit,允许core文件最大为1024k

ulimit -a        // 查看core文件size

用ulimit改变一下限制运行程序看看:
Linux进程信号之如何产生信号
运行程序之:
Linux进程信号之如何产生信号


2、产生方式二:调用系统函数向进程发信号
(1)kill函数(可以给一个指定的进程发送指定的信号)

函数原型:
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
返回值:成功返回0;错误时返回-1

还是刚才的程序,将它放在后台执行,然后用kill命令给他符SIGSEGV信号
Linux进程信号之如何产生信号
上面的命令还可以写成 kill -11 2581 ,11是信号SIGSEGV的编号。以往遇到的段错误都是由非法内存访问产生的,而这个程序本身没错,给它发SIGSEGV也能产生段错误。

(2)raise函数(给当前进程发送指定的信号 <自己给自己发信号>)

#include <signal.h>
int raise(int sig);
返回值:成功返回0;错误时返回-1

(3)abort函数(它使当前进程接受到信号而异常终止)

#include <stdlib.h>
void abort(void);
返回值:abort函数就像exit函数一样,总会成功,所以没有返回值

3、产生方式三:由软件条件产生信号

SIGPIPE和SIGALRM信号都是由软件条件产生的信号。下面主要讲alarm函数和SIGLARM信号

alarm函数

//函数原型
#include <unistd.h>
unsigned int alarm(unsigned int seconds);

//作用机制:
调用alarm函数可以设定一个闹钟,也就是告诉内核seconds秒之后给当前进程发SIGALRM信号,该信号默认处理动作是终止当前进程

// 返回值:返回值为0或者以前设置的闹钟时间还余下的秒数

举个例子来说明一下:
某人小睡一次,设定闹钟为30分钟之后响,20分钟后被人吵醒,还想再多睡一次,于是重新设定闹钟为15分钟之后响。“以前设定的闹钟时间还余下的时间”就是10分钟。
如果seconds值为0,表示取消以前设定的闹钟,函数的返回值仍然是以前设定的闹钟时间还余下的秒数。

来写个小程序吧!(1秒之内不停地数数,1秒到了之后就被SIGALRM信号终止)

#include <stdio.h>
#include <unistd.h>
int main()
{
      int count = 10;
    alarm(1);
    for (; 1; count++)
    {
            printf("count = %d\n", count);
    }

    return 0;
}

运行结果比较难截图,我就不截验证结果了,大家自己验证哦!

有关信号的阻塞,请戳此链接查看哦!
https://blog.csdn.net/apt1203jn/article/details/79997246