ktv支付订房网站模板,简单的报价表模板,北京到太原,河北省城乡住房和城乡建设厅网站目录 什么是信号#xff1f;
信号的产生
信号产生方式1#xff1a;键盘
前台进程
后台进程
查看信号
signal系统调用
案例
理解进程记录信号
软件层面
硬件层面
信号产生方式2:指令
信号产生方式3:系统调用
kill系统调用
案例
其他产生信号的函数调用
1.rais…目录 什么是信号
信号的产生
信号产生方式1键盘
前台进程
后台进程
查看信号
signal系统调用
案例
理解进程记录信号
软件层面
硬件层面
信号产生方式2:指令
信号产生方式3:系统调用
kill系统调用
案例
其他产生信号的函数调用
1.raise 2.abort
信号产生方式4:软件条件
什么是软件条件
alarm系统调用
使用
1.
2.
3.
信号的产生5:异常
示例1
示例2
那么os如何知道进程内部错误
理解一下野指针的异常
Term和Core的区别 什么是信号
信号信号量
信号是一种用户,OS,其他进程向目标进程发送异步事件的一种方式。
同步和异步 1.怎么识别信号
识别信号是内置的。即进程识别信号时程序的内置属性。可以类比一下语言的内置数据类型intdouble
2.信号产生后进程知道怎么处理吗知道 。如果没产生进程知道怎么处理吗也知道因为信号的处理方法在产生之前就已经准备好了。
3.信号会被进程立即处理吗
不一定如果不那么什么时候处理呢进程会在一个合适的时候处理。
信号到来 -- 进程不立即处理记录信号 -- 合适的时候处理信号
4.处理信号的方法 1.默认行为 2.忽略信号3.自定义动作 信号的产生 信号产生方式1键盘 这有一段死循环的程序
#include iostream
#include unistd.h
int main()
{while (true){std::cout hello world std::endl;sleep(1);}return 0;
}
从键盘中输入 ctrlc 可以前台进程杀掉前台进程。 前台进程
命令 ./程序名
运行起来的是前台进程也可以用ctrlc杀掉进程 后台进程 命令 ./进程名
后台进程无法用 ctrlc 杀死
杀掉后台进程的方法1. fg命令将后台进程切换到前台在ctrlc杀掉进程。 2. kill -9 pid(对应进程的pid
方法一 方法二 查看信号
kill -l man 7 signal//中可以找到相应信号的描述 signal系统调用
信号的自定义捕捉
signal的作用是捕捉signum号信号捕捉之后执行handler指向的函数 signum 要捕捉的信号
#define SIGQUIT 3
handler处理函数
案例 ctrl\ 默认终止进程 #include iostream
#include unistd.h
#include signal.h
void handler(int signo)
{std::cout signo: signo std::endl;
}
int main()
{//捕捉 3)SIGQUIT信号signal(SIGQUIT, handler);while (true){std::cout hello world std::endl;sleep(1);}return 0;
} ctrl\被捕捉不再执行默认行为默认终止而是将这个信号传给signo并调用自定义函数 根据上面的案例是不是我们捕捉所有信号那么这个死循环程序就不会被杀死了呢
#include iostream
#include unistd.h
#include signal.h
#include functional
using func_t std::functionvoid(int);
void handler(int signo)
{std::cout signo: signo std::endl;
}
int main()
{//signal(SIGQUIT, handler);//捕捉信号for(int i 1;i31;i){func_t f signal(i,handler);std::cout捕捉:istd::endl;}while (true){std::cout hello world std::endl;sleep(1);}return 0;
} 从结果上可以知道ctrlc ctrl\因为被捕捉了所以杀不掉进程但kill -9 可以 杀掉进程也就说明了9SIGKILL 不能被捕捉。 理解进程记录信号 软件层面
键盘比如ctrlc - os - 进程 -- 记录信号
因为os管理外设所以键盘将信号传给osos也管理进程os在将信号传给进程之后进程记录信号。 进程如何记录信号 总结
发送流程键盘中的信号发送给osos在发送给进程修改进程对应的信号位图和其维护处理方法的函数指针数组。 无论什么信号都是由os发送的。
os是task_struct的唯一管理者所以只有 os有权利修改信号位图。 硬件层面 os是如何知道键盘上有数据
轮徇不可以os的任务太多了
硬件中断
冯诺依曼体系结构 在数据层面上我们知道cpu不与外设直接打交道。而是通过存储器
但在cpu和键盘是连接的键盘可以直接将数据交给cpu 硬件中断 -- cpu告诉os键盘上有数据 -- 这样硬件和os就可以并行执行了 信号vs信号中断
信号是纯软甲的
信号中断是纯硬件的 信号产生方式2:指令
指令
kill -信号 相应进程的pid 信号产生方式3:系统调用 kill系统调用 kill的作用就是OS向pid)进程 发送sig信号 使用代码
#include iostream
#include unistd.h
#include signal.h
#include functional
#include sys/types.h
int main()
{int cnt 5;while(true){std::coutcntstd::endl;if(cnt0)kill(getpid(),SIGQUIT);sleep(1);cnt--;}return 0;
}
执行结果 kill()系统调用与kill命令的关系
kill命令行就是封装的kill()系统调用。 案例
简单实现下自己的kill
#include iostream
#include unistd.h
#include signal.h
#include functional
#include sys/types.hvoid Usage(char* argv)
{std::coutUsage error: argv signo pidstd::endl;exit(1);
}
//./kill 9 pidint main(int argc,char* argv[])
{if(argc!3){//正确使用提醒Usage(argv[0]);}int signo std::stoi(argv[1]);pid_t pid std::stoi(argv[2]);int ret kill(pid,signo);if(ret0){perror(kill);exit(2);}return 0;}
执行结果 其他产生信号的函数调用
1.raise
作用让OS向调用该函数的进程返送sig信号 2.abort
作用让OS向调用该函数的进程返送6号信号该进程被干掉 这两个函数比较简单 这两个函数都是由kill封装的,libc库函数
kill(getpid(),sig);//raise
kill(getpid(),6);//abort 信号产生方式4:软件条件 什么是软件条件
由软件条件产生信号通常指的是在软件应用程序中根据某些特定的条件或逻辑判断来触发或生成信号 比如管道中读端关闭但写端没有关闭 这时os回想进程发送 13SIGPIPE信号 alarm系统调用 作用设置一个seconds秒的闹钟时间一到就会给调用闹钟的进程发送 14SIGALRM信号 alarm(条件)
里面设置的时间就相当于条件满足条件就发送信号。 OS中维护的定时器的大概内核数据结构 使用
1.
#include iostream
#include unistd.hint main()
{alarm(1);int cnt 0;while(true){//一秒打印多少次std::coutcntstd::endl;cnt;}return 0;
}
结果
打印了11万多次快只能说很慢。 #include iostream
#include unistd.h
#include signal.h
#include functional
#include sys/types.hint cnt 0;
void handler(int signo)
{std::coutcntstd::endl;exit(0);
}
int main()
{alarm(1);signal(SIGALRM,handler);while(true){//std::coutcntstd::endl;cnt;}return 0;
} 结果计算了将近16亿次 从上面两个程序可以看出IO影响计算速度。
2.
#include iostream
#include unistd.h
#include signal.h
#include functional
#include sys/types.hint main()
{alarm(5);sleep(1);int n alarm(0);//alarm(0)取消闹钟 n上一个闹钟剩余的时间std::coutnstd::endl;return 0;
}3.
pause
作用等待信号 闹钟是一次性的发送完信号后就被取消。 #include iostream
#include unistd.h
#include signal.h
#include functional
#include sys/types.h
#include vector
using func_t std::functionvoid();int cnt 0;
std::vectorfunc_t v;//任务void handler(int signo)
{for (auto e : v){e();}alarm(2);cnt;
}
int main()
{v.push_back([](){ std::cout 我是一个日志任务 std::endl; });v.push_back([](){ std::cout 我是一个下载任务 std::endl; });v.push_back([](){ std::cout 我是一个mysql任务 std::endl; });alarm(2);//一次性闹钟超时后就会被取消signal(SIGALRM, handler);while (true){pause();//等待信号std::cout 我醒来了... std::endl;std::cout cnt: cnt std::endl;}
}
运行结果 将上述逻辑中的信号变为硬件中断就是OS的运行逻辑。
OS本质上就是一个中断处理程序 信号的产生5:异常 示例1
野指针
int main()
{int *p nullptr;*p 0;//野指针return 0;
}Segmentation fault 段错误
11)SIGEGV 示例2
int main()
{int a 10;a/0;return 0;
} Floating point exception 浮点异常
8SIGFPE 现在我们可以理解一下为什么程序会崩溃 出现错误时OS会向进程发送相应的信号从而进程被干掉。 那么os如何知道进程内部错误
比如div 0
cpu中有状态寄存器 EflagEflag中有个core dump溢出标记为标记为1.cpu计算错误 0.无错误 验证
#include iostream
#include unistd.h
#include signal.h
#include functional
#include sys/types.h
#include wait.hint main()
{pid_t pid fork();if(pid0){//子进程int a 10;a/0;}else{int status;waitpid(pid,status,0);std::coutcore dump: ((status7)1)std::endl;std::coutsigno: (status0x7F)std::endl;}
} 结果 正如所料core dump被设为1并向子进程发送8SIGFPE信号 -------------------------------------------------------------------------------------------------------------------------------- void handler(int signo)
{std::coutsigno: signostd::endl;
}
int main()
{pid_t pid fork();if(pid0){//子进程int a 10;a/0;}else{int status;waitpid(pid,status,0);std::coutcore dump: ((status7)1)std::endl;std::coutsigno: (status0x7F)std::endl;}
}
差不多的程序如果捕获了8号信号
结果 os一直发送8号信号。 总结
cpu错误 -- 谁弄坏了cpuos发送信号杀死进程 -- 如果捕捉了8号信号---进程没退出---还要调度--还要切换执行等 -- os不会修复Eflag中core dump1--一直触发信号 理解一下野指针的异常 野指针的错误是由cpu中MMU错误引起的 Term和Core的区别 Trem正常终止不需要debug
Core核心转储---在当前目录下形成core文件--进程崩溃将进程在内存中的部分信息保存起来方便以后调试--一般被云服务器关闭如果崩溃一次形成一个新的core那么就可能把磁盘空间占满 但当前目录下没有啊 如何打开
ulimit -a//查看 可以看到core file size为0
ulimit -c 大小//改变core file size readelf -S ./sig //查看程序elf格式 运行程序就可已生成core.pid的文件 如果无法生成core文件的话
在root下输入下面的命令就可以了
echo core /proc/sys/kernel/core_pattern
core-file core.pid//方便调试 如果是子进程异常呢core的生成条件
core dump-- 退出信号的终止动作是core 云服务器开启core