当前位置: 首页 > backend >正文

Linux进程信号(二)之信号产生1

文章目录

    • 产生信号
      • 1. 通过终端按键产生信号
        • Core Dump
      • 2.kill命令
      • 3. 调用系统函数向进程发信号
        • kill函数
          • 实现自定义kill命令
        • raise函数
        • abort函数

产生信号

1. 通过终端按键产生信号

SIGINT的默认处理动作是终止进程,

SIGQUIT的默认处理动作是终止进程并且Core Dump

键盘组合键

ctrl+c2号信号

ctrl+\3号信号

验证:

mysignal.cc

#include<iostream>
#include<unistd.h>
#include<signal.h>using namespace std;//int signum: 收到了哪个信号
void Handler(int signum)
{cout<<"process get a signal: "<<signum<<endl;
}int main()
{signal(3,Handler);//只需要设置一次,在进程生命周期内都有效。while(1){cout<<"I am a crazy process,pid: "<<getpid()<<endl;sleep(1);}return 0;
}

image-20250419220715133


不是所有的信号都可以被signal捕捉的。

验证:

mysignal.cc

#include<iostream>
#include<unistd.h>
#include<signal.h>using namespace std;//int signum: 收到了哪个信号
void Handler(int signum)
{cout<<"process get a signal: "<<signum<<endl;
}int main()
{for(int i=1;i<=31;i++){signal(i,Handler);}while(1){cout<<"I am a crazy process,pid: "<<getpid()<<endl;sleep(2);}return 0;
}

image-20250419221445846

image-20250419221557270

image-20250419221708965

验证可知,9号信号和19号信号不可以被捕捉,其他信号都可以。

一个是杀掉进程,一个是暂停进程。

Core Dump

11

image-20250421172726176

首先解释什么是 Core Dump

当一个进程要异常终止时,可以选择把进程的用户空间内存数据全部保存到磁盘上,

文件名通常是core,这叫做 Core Dump


进程异常终止通常是因为有Bug,比如非法内存访问导致段错误,

事后可以用调试器检查core文件以查清错误原因,

这叫做Post-mortem Debug(事后调试)。


一个进程允许产生多大的 core 文件取决于进程的 Resource Limit (这个信息保存 在PCB中)。

默认是不允许产生core文件的,

因为core文件中可能包含用户密码等敏感信息,不安全。

(云服务core dump功能是关闭的,因为很多服务器挂掉之后是会自动重启的,

如果该功能开启了,有些服务器挂了又重启,挂了又重启,每次挂了就core dump

一段时间后,磁盘空间的文件一下子就被转储文件占满了,就不是服务挂掉了而是操作系统挂了)。

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

首先用ulimit命令改变Shell进程的Resource Limit,

允许core文件最大为1024K: ulimit -c 1024

image-20250421232312596

mysignal.cc

#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>using namespace std;int main()
{pid_t id = fork();if (id == 0){int cnt = 500;while (cnt){cout << "I am a chid process,pid: " << getpid() << " ,cnt: " << cnt << endl;sleep(1);cnt--;}exit(1);}int status=0;pid_t rid=waitpid(id,&status,0);if(id==rid){cout<<"child quit info,rid: "<<rid<<" exit code: "<<((status>>8)&0xff)<<" ,exit sig: "<<((status&0x7f))<<" ,core dump: "<<((status>>7)&1)<<endl;// ? & (0000 0000 ... 0001)}return 0;
}

image-20250421232725487

ulimit命令改变了Shell进程的Resource Limit,

进程的PCB由Shell进程复制而来,

所以也具 有和Shell进程相同的Resource Limit值,这样就可以产生Core Dump了。

image-20250421232840260

是什么?

打开系统的core dump功能,

一旦进程出异常,OS会将进程在内存中的运行信息,

dump(转储)到进程的当前目录(磁盘)

形成core.pid文件:核心转储(core dump)。

为什么要进行核心转储呢?

这里的错误可以成为运行时错误。

直接复现问题之后,直接定位到出错行。

先运行后调试core-file(事后调试).

使用core文件(makefile要加-g):

mysignal.cc

#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>using namespace std;int main()
{int a=10;int b=0;a/=b;cout<<"a = "<<a<<endl;return 0;
}

image-20250421235207183

2.kill命令

kill -signo pid

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

kill函数

首先在后台执行死循环程序,然后用kill命令给它发SIGSEGV信号。

指定发送某种信号的kill命令可以有多种写法,
上面的命令还可以写成 kill -SIGSEGV pid 或 kill -11 pid,
11是信号SIGSEGV的编号。
以往遇到的段错误都是由非法内存访问产生的,
而这个程序本身没错,给它发SIGSEGV也能产生段错误。

kill命令是调用kill函数实现的。kill函数可以给一个指定的进程发送指定的信号。

image-20250419224632790

实现自定义kill命令

mykill.cc

#include<iostream>
#include<unistd.h>
#include<signal.h>
#include<sys/types.h>
#include<string>
#include<cstring>using namespace std;void Usage(string proc)
{cout<<"Usage:\n\t"<<proc<<" signum pid\n"<<endl;
}//kill signum pid
int main(int argc,char*argv[])
{if(argc!=3){Usage(argv[0]);exit(1);}int signum=stoi(argv[1]);int pid=stoi(argv[2]);int n=kill(pid,signum);if(n==-1){perror("kill");}return 0;
}

测试:

test.cc

#include <iostream>
#include <unistd.h>                                                                         
using namespace std;                  int main()                            
{                                     while(1)                          {                                                cout<<"I am a process,pid: "<<getpid()<<endl;sleep(1);}                                          return 0;                                  
}  

image-20250419230450432

raise函数

raise函数可以给当前进程发送指定的信号(自己给自己发信号)。

image-20250419230641249

#include <signal.h>
int kill(pid_t pid, int signo);
int raise(int signo);
这两个函数都是成功返回0,错误返回-1。

mykill.cc

#include<iostream>
#include<unistd.h>
#include<signal.h>
#include<sys/types.h>
#include<string>
#include<cstring>using namespace std;void Handler(int signum)
{cout<<"process get a signal: "<<signum<<endl;
}int main()
{signal(2,Handler);int cnt=0;while(1){cout<<"I am a process,pid: "<<getpid()<<endl;sleep(1);if(cnt%2==0){raise(2);//= kill(getpid(),2);}cnt++;}return 0;
}

image-20250419231241420

abort函数

abort函数使当前进程接收到信号而异常终止。

image-20250419231635954

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

mykill.cc

#include<iostream>
#include<unistd.h>
#include<signal.h>
#include<sys/types.h>
#include<string>
#include<cstdlib>
#include<cstring>using namespace std;void Handler(int signum)
{cout<<"process get a signal: "<<signum<<endl;
}int main()
{int cnt=0;while(1){cout<<"I am a process,pid: "<<getpid()<<endl;sleep(1);if(cnt%2==0){abort();//如果不考虑进程退出//abort就等于kill(getpid(),6);}cnt++;}return 0;
}

image-20250419231904825

加上自定义处理方式

signal(6,Handler);

image-20250419232054564

执行了自定义方法,但是最后还是退出了。

image-20250419232255539

while(1)
{cout<<"I am a process,pid: "<<getpid()<<endl;sleep(1);
}

image-20250419232429212

说明:

abort会捕捉自定义方法,信号捕捉完,还要返回调用行继续运行,让进程退出。

(与直接用 kill -6还是有区别的)

http://www.xdnf.cn/news/7193.html

相关文章:

  • 【Linux】第二十章 管理基本存储
  • Redis进阶知识
  • 数据库blog2_数据结构与效率
  • 选择之困:如何挑选合适的 Python 环境与工具——以 Google Colaboratory 为例
  • 0-1背包问题(求最优值和构造最优解)
  • 苍穹外卖--修改菜品
  • C++中的四种强制转换
  • web中路径问题
  • Leetcode134加油站
  • u深度学习 神经网络图像数据的预处理全解
  • RDD-数据清洗
  • 02 Nginx虚拟主机
  • 【Linux】第十七章 归档和传输文件
  • 为什么el-select组件在下拉选择后无法赋值
  • 机器学习西瓜书
  • 我的电赛(简易的波形发生器大一暑假回顾)
  • 字节跳动开源通用图像定制模型DreamO,支持风格转换、换衣、身份定制、多条件组合等多种功能~
  • 【android bluetooth 协议分析 01】【HCI 层介绍 4】【LeSetEventMask命令介绍】
  • 【C语言】字符串函数及其部分模拟实现
  • JavaScript:元宇宙角色动作与移动
  • 6.2.5图的基本操作
  • TYUT-企业级开发教程-第二章
  • 学习STC51单片机05(芯片为STC89C52RC)
  • 发布时将多个bpl 打包成一个bpl的方法,或者说:不需要vcl60.bpl情况下 18.5K的exe 照常可以运行。
  • deepseek系列论文汇总(时至2025.5)
  • 2023 睿抗机器人开发者大赛CAIP-编程技能赛-高职组(省赛)解题报告 | 珂学家
  • AGI大模型(24):通过LangChain的接口来调用OpenAI对话
  • 【AWS入门】Amazon Bedrock简介
  • Compose笔记(二十四)--Canvas
  • 项目:在线音乐播放服务器——基于SSM框架和mybatis