什么是信号
信号产生方式
键盘产生:
ctrl c:SIGINT 2号信号, 终止前台进程
ctrl \ :SIGQUIT 3号信号, 也是终止前台进程, 不过其action是core,有核心转储功能
指令
kill -9 pid :向指定进程发送9号信号
由于9号信号不可被用户自定义捕捉, 即kill -9 pid一定可以成功终止指定进程, 所以常用9号信号终止进程
系统调用
kill, raise, alarm, abort均为可发送信号的系统调用接口
异常
如代码中出现野指针, 除零等操作,
除零
若用户用signal函数自定义捕捉SIGFPE(11号, 浮点数错误,如除0)且自定义handler函数中没有退出exit,此进程会死循环(循环接收该信号,进入handler)
原因:CPU运算出错后Eflags(溢出标志位)置为1,且cpu数据随进程。每次调度该进程都保持Eflags=1,发送11信号,进入handler,不断循环
野指针
野指针也类似
MMU:memory manager unit
CR3:CR3 寄存器用于存储 页目录基址寄存器(Page Directory Base Register,PDBR)的值,它指向当前进程的页目录表(Page Directory)或页全局目录表(PGD)的位置,是进行 虚拟内存到物理内存的映射 过程中的关键寄存器。
EIP:在 x86 架构中,EIP(Extended Instruction Pointer)是一个关键的寄存器,它用于存储 CPU 当前正在执行的 指令地址,即 指令指针。它是一个 32 位寄存器(在 x86 体系结构中),用于跟踪程序执行的进度。
EIP中出现0指针/野指针时,由于无权访问就会报错(发信号),同上SIGFPE,每次调度该进程都会向进程发送信号,不断循环。
signal
core & term
core & term是什么
是不同信号有着不同退出模式(指令:man 7 signal)
term:进程正常退出
core(核心转储):在term基础上生成一个core.pid文件(pid为进程实际pid)
core功能有什么作用
便于事后调试
gbd中输入指令 core-file core即可直接查看进程退出原因,便于快速发现错误。
如何从status中获取core dump & SIG值
printf("exit signal: %d, core dump: %d\n", status&0x7F, (status>>7)&1);
为什么云服务器默认关闭core功能?
云服务器会循环重启退出的进程, 这会导致core文件大量堆积,直到云服务器崩溃。
有的云服务器会去掉core的pid后缀, 也可解决这个问题,但大多数云服务器选择直接关闭自动生成core文件的功能
如何生成core文件
产生core文件两个条件:
- 退出信号动作为core
- 服务器开启core功能
如何服务器开启core功能:
使用ulimit -a 查看core是否开启, ulimit -c 10240 开启core功能(即将core-file-size从0改为10240)
core dump标志
core dump在status的第八位
coredump可用于判断子进程是否生成core文件
code
#include <iostream>
#include <string>
#include <functional>
#include <vector>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
int main()
{
if (fork() == 0)
{
sleep(1);
int a = 10;
a /= 0;
exit(0);
}
int status = 0;
waitpid(-1, &status, 0);
printf("exit signal: %d, core dump: %d\n", status&0x7F, (status>>7)&1);
return 0;
}
// void handler(int signo)
// {
// std::cout << "get a signo: " << signo << std::endl;
// // 我捕捉了11/8号信号,没执行默认动作哦。也没有退出进程哦!
// }
// int main()
// {
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// // signal(8, handler);
// int a = 10;
// a /= 0;
// int *p = nullptr;
// *p = 100;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// std::cout << "hello world" << std::endl;
// // alarm(1);
// while(true);
// }
using func_t = std::function<void()>;
int gcount = 0;
std::vector<func_t> gfuncs;
// 把信号 更换 成为 硬件中断
void hanlder(int signo)
{
for(auto &f : gfuncs)
{
f();
}
std::cout << "gcount : " << gcount << std::endl;
alarm(1);
}
int main()
{
gfuncs.push_back([]()
{ std::cout << "我是一个内核刷新操作" << std::endl; });
gfuncs.push_back([]()
{ std::cout << "我是一个检测进程时间片的操作,如果时间片到了,我会切换进程" << std::endl; });
gfuncs.push_back([]()
{ std::cout << "我是一个内存管理操作,定期清理操作系统内部的内存碎片" << std::endl; });
alarm(1); // 一次性的闹钟,超时alarm会自动被取消
signal(SIGALRM, hanlder);
while (true)
{
pause();
std::cout << "我醒来了..." << std::endl;
gcount++;
}
}
// // void Handler(int signo)
// // {
// // // 当对应的信号被触发,内核会将对应的信号编号,传递给自定义方法
// // std::cout << "Get a signal, signal number is : " << signo << std::endl;
// // }
// // void Usage(std::string proc)
// // {
// // std::cout << "Usage: " << proc << " signumber processid" << std::endl;
// // }
// int number = 0;
// void die(int signumber)
// {
// printf("get a sig : %d, count : %d\n", signumber, number);
// exit(0);
// }
// // ./mykill 9 1234
// int main(int argc, char *argv[])
// {
// // 统计我的服务器1S可以将计数器累加多少!
// alarm(10); // 我自己,会在1S之后收到一个SIGALRM信号
// sleep(4);
// int n = alarm(0); // 0:取消闹钟
// std::cout << "n : " << n << std::endl;
// // signal(SIGALRM, die);
// // while(true)
// // {
// // number++;
// // // printf("count: %d\n", number++); // IO影响了计算速度!
// // }
// // int cnt = 5;
// // while(true)
// // {
// // std::cout << "hahaha alive" << std::endl;
// // cnt--;
// // if(cnt<=0)
// // // abort();
// // sleep(1);
// // }
// // if(argc != 3)
// // {
// // Usage(argv[0]);
// // exit(1);
// // }
// // int signumber = std::stoi(argv[1]);
// // pid_t id = std::stoi(argv[2]);
// // int n = ::kill(id, signumber);
// // if(n < 0)
// // {
// // perror("kill");
// // exit(2);
// // }
// // exit(0);
// // signal怎么不放在循环里面?
// // signal:如果没有产生2或者3号信号呢?Handler不被调用!
// // for (int signo = 1; signo < 32; signo++)
// // {
// // signal(signo, Handler); // 默认终止 -> 执行自定义方法:Handler
// // std::cout << "自定义捕捉信号: "<< signo << std::endl;
// // }
// // while (true)
// // {
// // std::cout << "hello world" << std::endl;
// // sleep(1);
// // }
// }
板书笔记
标签:status,core,产生,int,信号,进程,include From: https://blog.csdn.net/li_peixiansang/article/details/143600521