二 Linux进程间通信( 六 )

  • 内核态: 处于内核态的 CPU 可以访问任意的数据,包括外围设备,?如?卡、硬盘等,权限比较高
  • 注意: 操作系统中有一个cr寄存器来记录当前进程处于何种状态
    进程空间分为用户空间和内核空间 。此前我们介绍的页表都是用户级页表,其实还有内核级页表 。进程的用户空间是通过用户级页表映射到物理内存上,内核空间是通过内核级页表映射到物理内存上,如下面简图所示:
    二 Linux进程间通信

    文章插图
    二 Linux进程间通信

    文章插图
    • 当进程运行在内核空间时就处于内核态,而进程运行在用户空间时则处于用户态 。
    • 最高 1G 的内核空间是被所有进程共享的!
    进程有不同的用户空间,但是只有一个内核空间,不同进程的用户空间的代码和数据是不一样的,但是内核空间的代码和数据是一样的 。上面这些主要是想说:进程处于用户态访问的是用户空间的代码和数据,进程处于内核态,访问的是内核空间的代码和数据 。
    信号捕捉的整个过程:
    二 Linux进程间通信

    文章插图
    从上面的图可以看出,进程是在返回用户态之前对信号进行检测,检测pending位图,根据信号处理动作,来对信号进行处理 。这个处理动作是在内核态返回用户态后进行执行的,所以这里也就回答了开始提出的那一个问题了 。
    sigaction函数#include <signal.h>int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);功能:检查或修改指定信号的设置(或同时执行两种操作)参数:signum:要操作的函数act:要设置的对信号的新处理方式(传入方式)oldact:原来对信号的处理方式(传出参数)如果act指针非空,则要改变指定信号的处理(设置),如果oldact指针非空,则系统将此前指定信号的处理方式入oldact返回值:成功:0失败:-1struct sigaction结构体:
    struct sigaction { void(*sa_handler)(int);//旧的信号处理函数指针void(*sa_sigaction)(int, siginfo_t *, void *);//新的信号处理函数指针sigset_tsa_mask;//信号阻塞集intsa_flags;//信号处理的方式void(*sa_restorer)(void);//已经弃用};(1)sa_handler、sa_sigaction:信号处理函数指针,和signal里面的函数指针用法是一样的,根据情况给两个指针赋值 。
    ?a)SIG_IGN:忽略该信号
    ?b)SIG_DFL:执行系统默认的动作
    ?c)处理函数名:自定义信号处理函数
    (2)sa_mask:信号阻塞集,在执行信号处理函数的时候,用来临时的屏蔽信号
    (3)sa_flags:用于指定信号处理的行为,通常设置为0,表示使用默认的属性 。它可以是一下值的“按位”或“组合”:
    • SA_NOCLDSTOP:使父进程在它的子进程暂停或继续运行时不会收到SIGCHLD信号 。
    • SA_NOCLDWAIT:使父进程在它的子进程退出的时候不会收到SIGCHLD信号,这时子进程如果退出也不会成为僵尸进程 。
    • SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出整个信号 。
    • SA_RESETHAND:信号处理之后重新设置为默认的处理方式 。
    • SA_SIGINFO:使用sa_sigaction成员而不是sa_handler作为信号处理函数 。
    代码示例:
    #include <stdio.h>#include <unistd.h>#include <signal.h>void handler(int signo){printf("catch a signal: %d\n", signo);}int main(){struct sigaction act, oact;act.sa_flags = 0;// 选项 设置为0sigfillset(&act.sa_mask);act.sa_handler = handler;// 对2号信号修改处理动作sigaction(2, &act, &oact);while (1){raise(2);sleep(1);}return 0;}

    经验总结扩展阅读