二 Linux进程间通信( 三 )

运行结果小伙伴们自己下去运行一下吧~这里就不截图了
MMU产生异常: 当进程访问非法地址时,mmu想通过页表映射来将虚拟转换为物理地址,此时发现页表中不存在该虚拟地址,此时会产生异常,然后OS将异常解释为SIGSEGV信号,然后发送给进程
#include <stdio.h>#include <unistd.h>#include <signal.h>#include <stdlib.h>int main(){// MMU硬件产生异常,内核将这个异常处理为SIGSEGV信号发送给进程signal(11, handler);int* p = NULL;printf("%d\n", *p);return 0;}signal函数实现信号的捕捉#include<signal.h>typedef void(*sighandler_t)(int);//它定义了一个类型sighandler_t,表示指向返回值为void型(参数为int型)的函数(的)指针sighandler_t signal(int signum,sighandler_t handler);功能:注册信号处理函数(不可用于SIGKILL、SIGSTOP信号),即确定收到信号后处理函数的入口地址 。此函数不会阻塞 。参数:signum:信号的编号,这里可以填数字编号,也可以填信号的宏义 。handler:取值有3种情况:SIG_IGN:忽略该信号SIG_DFL:执行系统默认动作信号处理函数名:自定义信号处理函数,如:func回调函数的定义如下:void func(int signo){//signo为触发的信号,为signal()第一个参数的值}返回值:成功:第一次返回NULL,下一次返回此信号上一次注册的信号处理函数的地址 。如果需要使用此返回值,必须在前面先声明此函数指针的类型 。失败:返回SIG_ERR代码示例:
#include <stdio.h>#include <unistd.h>#include <signal.h>#include <stdlib.h>//信号处理函数void fun1(int signum){printf("捕捉到信号:%d\n",signum);}//信号处理函数2void fun2(int signum){printf("捕捉到信号:%d\n",signum);}//信号注册函数int main(){//信号注册//ctrl+csignal(SIGINT,fun1);//ctrl+\signal(SIGQUIT,fun2);while(1){sleep(1);}return 0;}运行结果如下:

二 Linux进程间通信

文章插图
信号先注册,进程不要退出,然后等待信号的到达,信号到达之后就会执行信号处理函数 。
阻塞信号了解几个概念:
  • 实际执行信号的处理动作称为信号递达
  • 信号递达的三种方式:默认、忽略和自定义捕捉
  • 信号从产生到递达之间的状态,称为信号未决(Pending)
  • 进程可以选择阻塞 (Block )某个信号
  • 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作
    注意:
    • 阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作
    • OS发生信号给一个进程,此信号不是立即被处理的,那么这个时间窗口中,信号就需要被记录保存下来,那么信号是如何在内核中保存和表示的呢?

二 Linux进程间通信

文章插图
每个进程都存在一个PCB,在PCB中存在两个集合,一个是未决信号集,一个是阻塞信号集 。
以SIGINT为例说明未决信号集和阻塞信号集的关系: