概念
在linux下执行以下 的命令,会出现如下的结果:
//以下显示的是系统定义的信号列表
@localhost ~]$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT
6) SIGABRT 7) SIGBUS 8) SIGFPE
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT
21) SIGTTIN 22) SIGTTOU 23) SIGURG
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4
shell可以同时运行一个前台进程和多个后台进程,只有前台可以接收到控制键产生的信号:例Ctrl+c。
前台运行过程中用户随时可能按下一个信号,该进程的用户空间代码执行到任何地方都有可能收到系统信号而终止,所以一信号相对于进程的控制流程来说是异步的。
信号是如何产生的?
用户在终端按下一些键的时候终端驱动环境就会发送信号给前台进程
- 硬件异常,硬件检测到异常之后报告给内核,然后内核向当前进程发送适当的信号(例:除0异常,内存访问错误,段错误)
- 一个进程进行了系统函数调用kill,raise,abort,会向进程发送信号。
软件条件:管道的读端已经关闭,但是仍然写数据,就会产生SIGPIPE的信号。而闹钟超时也会产生一个SIGALRM的信号。
处理方式
忽略此信号
进行该信号的默认行为:进程终止
- 捕捉信号:要求提供一个信号处理函数,在内核处理这个信号的时候转到用户执行处理函数。
- 附一个博主的博客链接,介绍的是捕捉信号的函数:https://blog.youkuaiyun.com/a1414345/article/details/71663379
- pause函数的实例:https://www.cnblogs.com/yxk529188712/p/4982401.html
如何实现信号的捕捉:出现异常后终端,系统调用进入到内核中;内核处理完异常准备返回用户状态之前,先处理当前进程中可以递送的信号(即实际处理信号的动作);自定义的信号处理函数回到用户状态执行函数;处理完之后在返回时执行特殊的系统调用再次进入内核;返回用户模式后,在上次中断的地方继续向下执行。
信号的阻塞
https://blog.youkuaiyun.com/stand__out/article/details/52039704
volatile
防止编译器对代码进行优化,举一个人简单的例子,在定义变量前加上volatile,说明这个被定义的变量的值是可变的。
include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
volatile int i=10;//每次都直接从内存中读取,而不是寄存器
int a=i;
cout<<a<<endl;
_asm
{
mov dword ptr [ebp-4],60
}
int b=i;
cout<<b<<endl;
getchar();
}
//正确结果为
10
60
竞态条件
- 由于进程线程的切换,导致程序出现逻辑错误。
可重入函数
- 两个不同的控制流程调用同一个函数,,访问时不会造成逻辑错乱。