文章目录
🚩预备工作
1,进程必须要能识别信号
2,进程即使没收到信号,也要知道怎么处理这些信号,处理信号能力是内核系统内置功能
3,进程收到信号,可能不会立即处理信号,等到合适时机再处理
4,进程收到信号,到处理信号,必然有时间窗口,也就是进程有保存信号已经发生的能力
🚩处理信号的三种模式:
1,默认
2,忽略
3,自定义
c
#include <iostream>
#include <unistd.h>
using namespace std;
int main()
{
while(1)
{
cout<<"i am a process"<<endl;
sleep(1);
}
return 0;
}
./process
为什么 cirl+c能杀掉进程?因为发送了终止信号
前台进程后台进程
杀掉的是前台进程,每次登录linux,会配一个bash,只允许一个进程是前台进程,其他的都是后台进程,键盘输入的是前台进程、
如果改为后台进程?
./process &

可以看到,我们甚至可以输入ls ,即使乱码了,,因为键盘输入发给前台进程,ctrl+c也杀不掉后台进程,
为什么乱码了也能执行ls?我们键盘有自己的缓冲区,只是我们输入的时候给显示器发送一份而已,而显示器又在接收其他进程,互相干扰乱码了,但是我们键盘缓冲区存储了ls
并且后台进程可以启动多份的
我可以多运行几次该程序,打印速度就会变快
ps ajx | grep mypocess
查到进程pid kill -9 杀掉
kill -l查看所有进程

ctrl + c向前台发送2号信号了,而2号信号默认又代表终止,怎么验证?
自定义信号

signal捕捉信号,再自己实现该信号功能,这就是自定义信号
c
#include <iostream>
#include <unistd.h>
#include <signal.h>
using namespace std;
void myhandler(int signo)
{
cout<<"get a signal: "<<signo<<endl;
}
int main()
{
signal(SIGINT,myhandler);//只需设置一次,往后都有效
while(1)
{
cout<<"i am a process"<<endl;
sleep(1);
}
return 0;
}

9号信号是捕捉不到的
硬件中断
讲解键盘输入:
键盘数据是如何传给内核的,ctrl+c又是如何变成信号的?
键盘与cpu针脚相连,硬件也有代号,比如说10,一旦键盘有数据,cpu就会感受到高低电位,同时cpu会让操作系统知道,把高低点位转换成10,同时操作系统有中断向量表,里面存储了硬件的操作方法,找到10代号的数组下标,把键盘数据拷贝到操作系统中,完成输入
同时操作系统会检测输入类型,如果是正常输入abc1234这种就拷贝,如果是组合键ctrl+c ctrl+v这种操作系统会当作信号传给进程


操作系统有键盘缓冲区,我们输入的东西如ls在键盘缓冲区,显示器也有缓冲区,我们的输入的东西都在显示器缓冲区,所以我们输入的ls和其他进程冲突了,显示器乱码了,但是键盘缓冲区还是正常的
如果键盘缓冲区不向显示器拷贝,就不会乱码了,比如lLnux输入密码时
🚩信号的产生
信号的产生和代码的运行是异步的
同步:同学出去上厕所,老师就停下讲课
异步:同学出去上厕所,老师继续讲课
1,键盘组合键
ctrl+c:2
ctrl+ \ : 3
2,kill 命令
kill -signo pid
不是所有信号都能被捕捉的
c
#include <iostream>
#include <unistd.h>
#include <signal.h>
using namespace std;
void myhandler(int signo)
{
cout<<"get a signal: "<<signo<<endl;
}
int main()
{
signal(SIGINT,myhandler);
signal(3,myhandler);
signal(19,myhandler);
while(1)
{
cout<<"i am a process"<<endl;
sleep(1);
}
return 0;
}
kill -19 pid之后

c
for(int i=1;i<=31;i++)
{
signal(i,myhandler);
}
将每个信号捕捉,然后kill -123456都杀一遍,就知道哪个信号不能被捕捉了
3,系统调用
kill
kill就是系统调用函数

我们可以自己实现kill了
c
void usage(string proc)
{
cout<<"usage:\n\t"<<proc<<" -signo pid"<<endl;
}
int main(int agrc,char* argv[])
{
if(agrc!=3)
{
usage(argv[0]);
exit(1);
}
int signo=stoi(argv[1]);
int pid=stoi(argv[2]);
kill(pid,signo);
return 0;
}

raise

raise向该进程发送一个信号,
c
int n=5;
while(n--)
{
cout<<"i am a process"<<endl;
}
raise(2);

其实相当于kill(getpid(),2);
abort

abort:发送6号信号,停止程序
c
signal(6,myhandler);
int n=5;
while(n--)
{
cout<<"i am a process"<<endl;
abort();
}

问题来了,我们捕捉了6号信号,可程序还是停止了,
说明abort发送6号信号,捕捉到了,返回myhandler函数后,继续执行abort函数,里面封装了停止程序代码
abort不能用kill来替代了
🚩最后:信号无论怎么产生,都是操作系统发给进程,
因为操作系统是进程的管理者
4,异常
异常也能产生信号
c
#include <iostream>
using namespace std;
int main()
{
int a=1;
int b=0;
a/=b;
cout<<"a/=b:"<<a/b<<endl;
return 0;
}


可以看到操作系统发送了8号信号
我们捕捉一下8号信号
c
void myhandler(int signo)
{
cout<<"get signo: "<<signo<<endl;
}
int main()
{
signal(8,myhandler);
int a=1;
int b=0;
a/=b;
cout<<"a/=b:"<<a/b<<endl;
return 0;
}

死循环了 !
为什么呢?
除0错误是cpu硬件产生的异常
cpu有保存上下文的寄存器eip/pc,也有状态寄存器,当除0或溢出时会将0置1,同时,进程切换会带自己的数据,也就是说,如果一个进程崩溃,它不会影响其他进程,此进程状态寄存器是1,其他进程来的时候就是0,但是如果除0时候进程不崩溃,该代码就会一直被调度,切换时一直出错误,通知操作系统不断向进程发信号,导致死循环了

野指针错误呢?
也是cpu产生异常
野指针在页表MMU硬件单元中转换失败,cpuCR2寄存器会记录

记住,异常只是让我们死的明白,知道怎么错了,不是让我们解决的,大部分情况是直接退出
5,软件产生异常
异常不是只有硬件产生,
当管道文件,关闭读端时,再向里面写数据就会报错

alarm

闹钟,设定几秒后终止进程,发送14号信号
c
int main()
{
int n=alarm(5);
while(1)
{
cout<<"i am a process:"<<getpid()<<endl;
sleep(1);
}
cout<<n<<endl;
return 0;
}

返回值:返回上一个闹钟剩余时间,我们设多个闹钟时,重新设置的闹钟返回值是上一个闹钟的剩余时间
c
void myhandler(int signo)
{
cout<<"get signo: "<<signo<<endl;
int n=alarm(5);
cout<<n<<endl;
}
int main()
{
signal(14,myhandler);
int n=alarm(50);
while(1)
{
cout<<"i am a process:"<<getpid()<<endl;
sleep(1);
}
cout<<n<<endl;
return 0;
}

提前触发闹钟,重新设置,发现剩余时间25s
操作系统中有很多闹钟,先描述再组织
闹钟结构体,肯定有时间戳,获取当前时间,比对设置时间,用最小堆组织起来,如果堆顶没超时,则所有闹钟没超时
core核心转储
man 7 signal

term是终止
进程等待有这副图,我们只用低16位,其中第8位给core dump标志位,低7位给信号,次低8位给退出码

c
int main()
{
int n = fork();
if (n == 0)
{
int cnt = 50;
while (cnt--)
{
cout << "i am child getpid():" << getpid() << endl;
sleep(1);
}
exit(2);
}
int status;
pid_t rid = waitpid(-1, &status, 0);
cout<<"exit code:"<<((status>>8)&0xFF)<<"signal code:"<<(status&0x7F)<<"core dump code:"<<(status>>7&1)<<endl;
return 0;
}

当发送8号信号时,core dump没有置1,为什么??
因为云服务器把core关了
我们打开
ulimit -a 查看所有限制,ulimit -c 设置


现在置1了,有什么用呢?
首先它一定是运行时出错,core将内存中的数据转存到磁盘当前目录(core文件)中
我们还能看到core文件,

可以gdb进行调试,能看到出错在哪一行
c
int main()
{
int a=1;
int b=0;
a/=b;
cout<<"a/=b:"<<a/b<<endl;
return 0;
}

那为什么要禁掉core呢?
因为公司服务器挂掉时,会尝试重启,计算机计算很快,而一点小错误不断重启,磁盘瞬间被core文件填满,到时候操作系统直接挂掉了
