Linux进程信号--1、信号产生
目录
一、键盘产生
1.1产生过程
1.2过程图示(硬 + 软)
1.3代码演示
二、Linux指令
三、系统调用
3.1本质
3.2举例
3.2.1 kill
3.2.2 raise
3.2.3 abort
四、软件条件
4.1 理解
4.2 alarm演示
4.2.1基于alarm实现理解OS运行
五、异常
5.1 理解
5.2 举例
5.3 core dump 与 Term
一、键盘产生
1.1产生过程
键盘组合键(快捷键)按下被OS识别,在PCB中修改位图结构(前32个信号)(后面的信号为实时信号用不到)由0->1->0,根据比特位上的位置从对应的执行方法结构体函数指针数组上获得信号对应方法并执行。
注:
1.硬件信号处理理解与执行过程详见中断之OS运行
2.信号位图只能由OS改写,因为OS是进程的管理者
3.软件信号处理理解
1.2过程图示(硬 + 软)
1.3代码演示
Ctrl+C (SIGINT) 已经验证过,这⾥不再重复Ctrl+\(SIGQUIT)可以发送终⽌信号Ctrl+Z(SIGTSTP)可以发送停⽌信号,将当前前台进程挂起到后台.......
#include <iostream>
#include <unistd.h>
#include<signal.h>
#include<sys/types.h>void handler(int signum)
{std::cout << "我是: " << getpid() << ", 我获得了⼀个信号: " << signum << std::endl;exit(0);
}int main()
{std::cout << "我是进程: " << getpid() << std::endl;// //ctrl+\// signal(SIGQUIT/*3*/, handler);// //ctrl + z// signal(SIGTSTP/*20*/, handler);while(true){std::cout << "I am a process, I am waiting signal!" << std::endl;sleep(1);}
}
二、Linux指令
kill - SIGNUM PID
-9信号无法被捕捉
三、系统调用
3.1本质
代码中利用函数调用系统调用系统调用,利用软中断向OS发送信号
3.2举例
3.2.1 kill
kill 命令是调⽤ kill 函数实现的。 kill 函数可以给⼀个指定的进程发送指定的信号。NAMEkill - send signal to a processSYNOPSIS#include <sys/types.h>#include <signal.h>int kill(pid_t pid, int sig);RETURN VALUEOn success (at least one signal was sent), zero is returned. On error, -1 is returned, and errno is set appropriately.
void Usage(char *argv[])
{std::cerr << "Usage: " << argv[0] << " -signumber pid" << std::endl;
}int main(int argc,char *argv[])
{//函数调用系统调用//1.自主实现killif(argc != 3){Usage(argv);return 1;}int number = std::stoi(argv[1]+1); // 去掉-pid_t pid = std::stoi(argv[2]);int n = kill(pid, number);return n;
}
3.2.2 raise
raise 函数可以给当前进程发送指定的信号(⾃⼰给⾃⼰发信号)。NAMEraise - send a signal to the callerSYNOPSIS#include <signal.h>int raise(int sig);RETURN VALUEraise() returns 0 on success, and nonzero for failure.
//2.raisesignal(2, handler); // 先对2号信号进⾏捕捉// 每隔1S,⾃⼰给⾃⼰发送2号信号while(true){sleep(1);raise(2);}
3.2.3 abort
abort 函数使当前进程接收到信号⽽异常终⽌。NAMEabort - cause abnormal process terminationSYNOPSIS#include <stdlib.h>void abort(void);RETURN VALUEThe abort() function never returns.// 就像exit函数⼀样,abort函数总是会成功的,所以没有返回值
//3.abortsignal(SIGABRT, handler);while(true){sleep(1);abort();}
四、软件条件
4.1 理解
软件条件不满足,导致发生软中断引发信号产生
eg:
1.管道读端关闭,继续写OS就会杀掉该进程(13)号信号
2.设置闹钟函数alarm()(14号信号)
4.2 alarm演示
NAMEalarm - set an alarm clock for delivery of a signalSYNOPSIS#include <unistd.h>unsigned int alarm(unsigned int seconds);RETURN VALUEalarm() returns the number of seconds remaining until any previously scheduled alarm was due to be delivered, or zero if there was no previ‐ ously scheduled alarm.
4.2.1基于alarm实现理解OS运行
#include <iostream>
#include <unistd.h>
#include<signal.h>
#include<functional>
#include<vector>
#include<sys/types.h>//基于alarm实现理解OS运行using func_t = std::function<void()>;int gcount = 0;
//OS任务集
std::vector<func_t> gfuncs;// 把信号 更换 成为 硬件中断
void hanlder(int signo)
{for(auto &f : gfuncs){f();}std::cout << "gcount : " << gcount << std::endl;//持续发送14号信号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);signal(SIGALRM,hanlder);while(true){pause();gcount++;std::cout << "我醒来了..." << std::endl;}return 0;
}
五、异常
5.1 理解
硬件异常被硬件以某种⽅式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号。例如当前 进程执⾏了除以0的指令, CPU的运算单元会产⽣异常, 内核将这个异常解释为SIGFPE信号发送给进 程。再⽐如当前进程访问了⾮法内存地址, MMU会产⽣异常,内核将这个异常解释为SIGSEGV信号发送 给进程。
5.2 举例
a.野指针 :段错误--11号信号b.除0 :浮点数错误 --8号信号
#include <stdio.h>
#include <signal.h>
void handler(int sig)
{printf("catch a sig : %d\n", sig);
}
int main()
{//signal(SIGSEGV, handler);sleep(1);int *p = NULL;*p = 100;while(1);return 0;
}
#include <stdio.h> 1
#include <signal.h>
void handler(int sig)
{printf("catch a sig : %d\n", sig);
}
// v1
int main()
{//signal(SIGFPE, handler); // 8) SIGFPEsleep(1);int a = 10;a/=0;while(1);return 0;
}
5.3 core dump 与 Term
利用man 7 signal查看时我们会发现终止信号的处理方法分为Core 和 Term,其中Term是正常终止,但Core会产生dump文件用于事后调试(gdb)


