【Linux入门】进程信号(1)

进程信号

  • 信号入门
    • 信号
    • 技术应用角度的信号
    • 信号概念
    • 用kill -l命令查看系统定义的信号列表
    • 信号处理常见方式的概览
  • 进程记录信号的方式
  • 产生信号
    • 通过终端按键产生信号
    • 调用系统函数向进程发信号
  • 信号捕捉-初识


信号入门

信号

在生活的角度,我们随时随地不可能收到信号,比如我们在过马路的时候,看到了绿灯就过去,红灯就停止;在上学的时候,听到了下课铃声就高兴飞起。其本质就是我们知道这个信号是干嘛的,我们可以识别信号并处理信号,在进程角度也是如此。

信号产生前:信号还没有产生的时候,对应普通人来讲,我们是有足够的知识知道这个信号来了我们该怎么做,进程也是如此(进程内部一定能够识别信号,程序员已经在编写设计进程的时候已经内置了处理方案)(信号属于进程内部特有的特征)。
信号产生中:信号已经来了,但是进程不一定要立即处理(时间窗口),因为有可能正在做优先级更高的事情,这个时候进程需要用某种方式来记录这个信号。
准备处理信号:处理信号的三种方式:默认行为、自定义行为、忽略行为。
用买快递来形容这三种行为。

  • 默认行为:拿到看快递,就幸福的打开快递,使用商品。
  • 自定义行为:快递拿来了,送给别人,这个快递你想怎么处理就怎么处理。
  • 忽略行为:快递拿来了,就放在那压灰,从此之后不管这个快递。

信号产生的过程与进程是属于异步关系,不会相互干扰。

技术应用角度的信号

之前我经常用Ctrl+C来结束进程,在我们按Ctrl+C的时候,键盘是产生了硬件中断,被OS获取,解释为信号,发生给目标前台进程,进程收到这个信号,进而引起进程退出。

#include
#include
int main()
{
	while(1){
		printf("1\n");
		slepp(1);
	}
	return 0;
}

进程接收到系统获取Ctrl+C解释的信号的处理方式是属于默认行为。

注意
Ctrl-C 产生的信号只能发给前台进程。一个命令后面加个&可以放到后台运行,这样Shell不必等待进程结束就可以接受新的命令,启动新的进程。
Shell可以同时运行一个前台进程和任意多个后台进程,只有前台进程才能接到像 Ctrl-C 这种控制键产生的信号。
前台进程在运行过程中用户随时可能按下 Ctrl-C 而产生一个信号,也就是说该进程的用户空间代码执行到任何地方都有可能收到 SIGINT 信号而终止,所以信号相对于进程的控制流程来说是异步(Asynchronous)的。

信号概念

信号是进程之间事件异步通知的一种方式,属于软中断。

用kill -l命令查看系统定义的信号列表

kill -l查看系统定义的进程。
【Linux入门】进程信号(1)_第1张图片
共有62个信号,其中白色的是普通信号,黑色的是实时信号。
这些信号都是宏表示的。
使用

通过vim /usr/include/asm-generic/signal.h可以看到
【Linux入门】进程信号(1)_第2张图片

信号处理常见方式的概览

(sigaction函数稍后详细介绍),可选的处理动作有以下三种:

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

进程记录信号的方式

我们通过kill -l命令知道普通信号是31个,一字节32比特位,通过这些我们可以判断记录信号的方式是通过位图。而这个位图是在PCB中的。

0000 0000 0000 0000 0000 0000 0000 0000 0000
比特位的位置:信号的编号
比特位的内容:是否收到信号

进程收到信号本质是进程位图被修改了,且只要OS才有资格来修改信号位图。

产生信号

通过终端按键产生信号

我们有很多个组合键入Crtl+C,这些是通过终端按键来给进程发信号的。
其中Ctrl+C是SIGINT信号。SIGINT的默认处理动作是终止进程,SIGQUIT的默认处理动作是终止进程并且Core Dump,现在我们来验证一下。

首先解释什么是Core Dump。当一个进程要异常终止时,可以选择把进程的用户空间内存数据全部 保存到磁盘上,文件名通常是core,这叫做Core Dump。进程异常终止通常是因为有Bug,比如非法内存访问导致段错误,事后可以用调试器检查core文件以查清错误原因,这叫做Post-mortem Debug(事后调试)。一个进程允许产生多大的core文件取决于进程的Resource Limit(这个信息保存 在PCB中)。默认是不允许产生core文件的,因为core文件中可能包含用户密码等敏感信息,不安全。在开发调试阶段可以用ulimit命令改变这个限制,允许产生core文件。 首先用ulimit命令改变Shell进程的Resource Limit,允许core文件最大为1024K: $ ulimit -c1024

我们通过ulimit -a查看core的大小。
【Linux入门】进程信号(1)_第3张图片
通过ulimit -c 1024修改core大小
在这里插入图片描述
编写一段除0错误的代码,在运行之后会产生一个core.xxx文件,xxx是这个进程的id。

#include
int main()
{
  int a=1/0;
  return 0;
}

【Linux入门】进程信号(1)_第4张图片

调用系统函数向进程发信号

通过kill命令对进程发信号
比如发生2号信号

kill -2 进程的PID
kill -SIGQUIT 进程的PID

信号捕捉-初识

信号是可以自定义捕捉的,使用到的函数是signal.

#include
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
参数:signum:捕捉的是几号信号
	 sighandler:捕捉到的信号的处理方式
返回值:signal()返回信号处理程序的上一个值。
	   如果发生错误,则设置errno以指示原因。

代码实现:

#include
#include
#include

void sighand(int sig)
{
  printf("catah a sig:%d \n",sig);

}
int main()
{
    int signo=1;
    for(signo=1;signo<=31;signo++){
      signal(signo,sighand);
    }
    while(1){
      sleep(1);
    }    
  return 0;
}

【Linux入门】进程信号(1)_第5张图片
在我们之前的博客中有提到status,其中第8个比特位我们没有说,其实第8个比特位是来表示有没有core。

我用代码验证一下:

#include
#include
#include
#include
#include
#include

int main()
{
  if(fork()==0){

    int a=1/0;
    exit(1);
  }
  int status=0;

  waitpid(-1,&status,0);
  printf("code:%d - core:%d - sig:%d \n",
      (status>>8)&0xFF,(status>>7)&1,status&0x7f);
	return 0;
}

在这里插入图片描述


你可能感兴趣的:(Linux,linux)