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

一、信号概念

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

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

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

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

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

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


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

我们先来写一个死循环的小程序:(如下图所示)
这里写图片描述
这里写图片描述
运行结果:
这里写图片描述
运行之,发现去掉信号捕捉,键入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改变一下限制运行程序看看:
这里写图片描述
运行程序之:
这里写图片描述


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

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

还是刚才的程序,将它放在后台执行,然后用kill命令给他符SIGSEGV信号
这里写图片描述
上面的命令还可以写成 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

阅读更多
个人分类: Linux
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭