目录
一.进程状态
二.信号捕捉时机与流程
三.sigaction函数
四.SIGCHLD信号
一.进程状态
linux将进程的状态分为用户态(user mode)和内核态(kernel mode)。
内核态时CPU执行代码不受任何限制,而用户态会做代码安全的相关检查,不能直接访问内核数据。一般而言,执行代码不会进入内核态,防止用户破坏内核数据和操作系统。
但有时需要进入内核态,比如当执行系统调用接口时就是典型进程状态转换过程。
以执行系统提供的open函数,其过程如下:
1.进程执行到open的代码,CPU取得open函数地址。(用户态)
2.跳转到open函数地址(在虚拟地址空间的内核区)。(用户态)
3.页表映射到物理内存中open函数的位置。(用户态)
4.真正开始执行open函数。(用户态)
5.open函数内部使用中断interrupt 80使CPU中断。(用户态)
6.CPU中断后,其中CR3寄存器由用户态改为内核态。
7.继续执行open内部代码
8.open函数执行完毕后,操作系统再将CPU内部寄存器改为用户态。
二.信号捕捉时机与流程
信号的捕捉时机是进程由内核态转为用户态时。
信号捕捉的具体流程如下图所示:
如果信号函数是自定义的那么需要先切换成用户态去执行自定义函数,之所以不直接在内核态执行,是因为内核态不会检查代码安全,防止自定义函数中有破坏内核的代码危害系统安全。
由此,我们不难发现,如果按照自定义函数的处理方式,那么信号捕捉的过程就是四个状态的转化。
即用户态->内核态->用户态->内核态->用户态。
图形表示大致如下:
三.sigaction函数
sigaction函数用于自定义信号函数
第一个参数为信号值。
第二个参数是sigaction类型指针。
sigaction是linux自带的类型,本质是一个结构体。
第三个参数也是sigaction类型,是输出型参数,接收旧的sigaction类型对象。
使用方式如下:
void func(int signum){
cout << "发送2号信号" << endl;
}
int main(){
struct sigaction sa, oldsa;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);//block位图置为0,全不阻塞
sa.sa_handler = func;//使用自定义函数
sigaction(2, &sa, &oldsa);
sleep(3);
return 0;
}
四.SIGCHLD信号
当子进程暂停或退出时会向父进程发送该信号。
默认处理方式为忽略,子进程退出后若父进程不回收将变成僵尸进程。
但是,该信号存在特殊情况,即当使用signal函数自定义处理方式为SIG_IGN时,虽然处理方式依旧是忽略,但此时若子进程退出将不会变成僵尸进程而是父进程直接回收。
演示如下:
若直接采用默认的忽略处理方式:
如果自定义SIG_IGN:
signal(SIGCHLD, SIG_IGN);
简单不先于复杂,而是在复杂之后 —— Alan Perlis
如有错误,敬请斧正