• 进程 信息


    基本概念

    软件中断
    通知一个进程发生了某个事件,打断进程当前操作,去处理这个事件

    信号:多种多样且能够被识别的

    查看信号种类

    kill -l
    62 种信号
    1 ~ 31 :非可靠信号,非实时信号
    34 ~ 64:可靠信号,实时信号

    在这里插入图片描述

    信号的生命周期

    信号的生命周期:产生、注册、注销、处理、阻塞

    产生

    硬件产生

    ctrl+c:终止一个进程
    ctrl+z:停止一个进程,只是暂停运行
    ctrl+\:quit

    软件产生

    (1)kill 指令

    kill 指令
    kill 进程号:杀死一个进程,本质上是给指定进程发送一个终止信号,而进程收到信号后,对信号的处理就是退出运行

    在这里插入图片描述

    int kill(pid_t pid,int signum);
    给指定进程发送一个指定的信号值

    getpid() :获取当前程序进程号

    在这里插入图片描述
    在这里插入图片描述

    bt:查看函数调用栈

    (2)raise

    int raise(int signum);
    给进程自身发送一个指定的信号值

    (3)abort

    abort();
    给进程自身发送一个 SIGABRT 信号
    在这里插入图片描述

    (4)alarm

    int alarm(int sec);
    sec 秒之后给进程发送 SIGALRM 信号
    定时器,时间到了之和给进程自身发送一个 SIGALRM 信号值

    在这里插入图片描述

    #include 
    #include
    #include 
    
    void mysleep(int n)
    {
      alarm(n);     //设置 alarm 信号
      pause();
    }
    
    void sigcb()
    {
      printf("3s 已经结束!\n");
    }
    
    int main()
    {
      signal(SIGALRM,sigcb);  //信号中断
      
      mysleep(3);       // alarm 
    
      while(1){            //此时进行了信号中断操作,因此会继续执行下列代码
        printf("use alarm!\n");
        sleep(2);
      }
    
      return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    在这里插入图片描述

    有个进程 KILL 杀不死,原因是什么?

    (1)当前进程是一个僵尸进程

    (2)可能是停止状态(T)----- 对信号不出来

    (3)信号可能被阻塞,或者被自定义处理了。

    注册

    让一个进程能够知道自己收到了某个信号-----在进程中做记号

    在进程 pcb 中有个 sigpending 未决信号集合(是个位图);
    进程的 PCB 中有个 sigqueue 链表,添加收到的信号链表,收到一次信号添加一个节点。

    未决信号---------还没有被处理的信号
    在这里插入图片描述

    非可靠信号

    若没有收到这个信号则注册一下(添加一个新节点,位图置为 1),若之前已经收到了这个信号还未处理则什么都不做(丢弃)

    可靠信号

    不管位图是否为 1(是否已经注册,还没处理),都会添加一个信号节点

    flag 1 : 将一个进程调到前台运行

    注销

    在信号被处理之前,消除信号存在的痕迹(主要是防止信号被重复处理)

    (1)非可靠信号的注销

    删除信号的信息节点,位图置为 0

    (2)可靠信号的注销

    删除信号的一个信息节点,当没有相同节点则位图置为 0

    处理

    调用信号的事件处理函数

    三种信号处理方式

    (1)默认处理:系统中已经预定好的处理方式

    (2)忽略处理:空的处理方式

    (3)自定义处理方式:自己定义一个处理函数,替换掉处理函数

    接口

    sighandler_t signal(int signum,sighandler_t handler);

    typedef void(*sighandler_t)(int); //函数

    handler:
    SIG_DFL:信号默认处理方式
    SIG_IGN:忽略处理

    功能:使用 handler 函数,替换掉 signum 信号当前的处理函数-----意味着进程收到 signum 信号,则使用 handler 函数进行处理

    练习:
    在这里插入图片描述

    发现当前程序运行使用 ctrl+c 中断不起作用------因为使用的信号中断----------- ctrl + / 退出 或者 kill (ps -ef | grep signal)

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    自定义处理方式的信号捕捉流程

    在这里插入图片描述

    阻塞

    信号依然会注册,但是暂时不处理(直到被解除阻塞)

    进程 PCB 中有个 block 阻塞信号集合,哪个信号被添加到了 block 集合中,就表示如果收到了也暂时不处理

    接口

    int sigprocmask(int how,sigset_t *set,sigset_t *old);

    (1) how:要对 PCB 中信号阻塞集合进行的操作
    SIG_BLOCK:block |=set ; 将 set 集合中的信号添加到 block 中
    SIG_UNBLOCK:block &=~set ;将 set 中的信号解除阻塞
    SIG_SETMASK:block=set
    (2)old:将修改前 block 集合中的信息添加到 old ,便于还原
    返回值:失败返回 -1,成功 0

    #include

       int sigemptyset(sigset_t *set);    //清空集合 set
    
       int sigfillset(sigset_t *set);          //将所有信号加载到 set 集合
    
       int sigaddset(sigset_t *set, int signum);   //将某一个信号添加到 set 
    
       int sigdelset(sigset_t *set, int signum);   //删除 set 中某个信号
    
       int sigismember(const sigset_t *set, int signum);   //查找某个信号
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    代码练习:

      1 #include                                                     
      2 #include
      3 #include
      4 #include
      5 
      6 void sigcb(int no)
      7 {
      8   printf("no = %d\n",no);
      9 }
     10 
     11 int main()
     12 {
     13   signal(SIGINT,sigcb);   //修改 2 号信号处理方式-----------非可靠信号    ,多次收到但只会注册一次
     14   signal(SIGRTMIN+5,sigcb);  //修改 39 号信号的处理方式----------可靠>    信号,多次收到就会注册多次
     15 
     16   sigset_t set,old;
     17   sigemptyset(&set);  //清空集合
     18   sigemptyset(&old);
     19   sigfillset(&set);  //将所有信号填充到 set 集合
     20 
     21   sigprocmask(SIG_BLOCK,&set,&old);  //信号阻塞
     22   printf("按回车继续运行!\n");
     23   getchar();
     24 
     25   sigprocmask(SIG_UNBLOCK,&set,NULL);   //解除阻塞
     26  // sigprocmask(SIG_SETMASK,&old,NULL); //还原旧信号
     27 
     28   while(1)
     29     sleep(1);
     30   return 0;
     31 }                      
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    在这里插入图片描述

    实时信号先进行处理,非实时信号后处理

    注意

    两个特殊信号--------不可被阻塞,不可被自定义,不可被忽略:

    kill -9 信号编号:杀死信号
    kill -19 信号编号

    信号应用

    (1)自定义或忽略 SIGPIPE 信号
    管道所有读端被关闭,继续 write 会触发异常
    (2)自定义或忽略 SIGCHLD 信号
    子进程退出时给父进程发送信号,然后成为僵尸进程,只不过因为信号默认处理为忽略,因此子进程退出并没有得到处理--------------进程等待 wait
    signal(SIGCHLD,SIG_IGN);

    关键字 volatile

    作用:修饰一个变量,保持变量的内存可见性。

    要求 CPU 在进行变量处理时候,每次都重新到内存获取数据进行处理

    编译器若认为某个值 cpu 经常访问到,多次从内存读取太慢--------编译器优化:直接将这个值放在寄存器当中,每次不需要从内存中读取数据--------------但这种做法有时候是不合理的

    函数重入

    一个程序的运行,可能存在多个执行流程
    若一个函数同时在多个执行流程中,进入执行,就叫做函数重入

    可重人

    一个函数在多个执行流程中重入之后,并不会产生一些异常或预期之外的情况。

    不可重入

    一个函数在多个执行流程中重入之后,有可能会产生一些数据二义性、导致产生预期之外的结果。

        1 #include                                                   
        2 #include
        3 #include
        4 #include
        5 
        6 int a=1,b=1;
        7 void test(char* str)
        8 {
        9   printf("%s----start-------\n",str);
       10   a++;
       11   b++;
       12   printf("%s-%d\n",str,a+b);        //产生数据二义性
       13  
       14   printf("%s-----end-------\n",str);
       15 }
    W> 16 void sigcb(int no)
       17 {
    W> 18   test("sigcb");
       19 }
       20 int main()
       21 {
       22   signal(SIGINT,sigcb);
    W> 23   test("main");
       24   sleep(2);
       25   return 0;
       26 }              
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在这里插入图片描述

    ps:
    欢迎评论留言哦~~~

  • 相关阅读:
    Docker学习(3)—— 将容器转化为新的镜像,并将新镜像发布到阿里云公共仓库或私有仓库
    java面向对象(六)
    深度学习-全卷积神经网络(FCN)
    静态网卡配置centos、kali、ubantu
    在一台电脑上安装多个python版本(小白教程)
    vue转electron项目以及使用fs报错:Module not found: Error: Can‘t resolve ‘fs‘ in解决办法
    如何做好项目管理?项目管理和团队协作是关键
    读 RocketMQ 源码,学习并发编程三大神器
    SLAM第11讲
    TypeScript快速上手
  • 原文地址:https://blog.csdn.net/weixin_46655027/article/details/127803594