• 进程信号;



    (一)信号;

    要弄懂信号,就需要 理解信号的三种情况 与处理 

    (1)信号有哪些?

    1. //查看系统 信号
    2. kill -l

    这些信号,在系统里本质上就是一堆宏定义;

    vim /usr/include/bits/signum.h

    (2)信号怎传输的?

     所以一个进程收到信号,本质上就是因为PCB内 位图被修改!!!

    换句话说,就是由 操作系统(OS)修改数据!

    信号如何发送?

    本质就是操作系统 去修改进程PCB内的位图!


    (二)信号的产生;

    (0)前言 我们先来一个现象;

    此时收到键盘的ctrl + C 后程序终止;

    原因是,把ctrl + C 解释 成了 2号信号;

    口说无凭,我们现在来认识下面的一个捕捉信号的函数

    #include

    typedef void(*sighandler_t)(int)

    sighandler_t signal(int signum,sighandler_t handler);

     

    收到了信号(ctrl + C)

    但为什么此刻程序不终止了??

    是因为这个捕捉函数,在捕捉的时候,也把默认行为 改为自定义行为了~ 

    (2)Core Dump与信号;

    core dump叫做事后调试,会把进程运行中的数据,转储在磁盘上。(core.pid);

    1. //查看 核心存储
    2. ulimit -a

    1. //设置核心转储
    2. ulimit -c 10240

    核心转储这里出现问题;

     本质上是因为收到8信号;

    8号信号也就是浮点数错误; 

     那么就有个问题,为什么进程会发生崩溃?

    进程发生崩溃的本质原因在于;接收到了OS的信号。

     那么OS怎么知道存在问题呢?是因为在硬件上有所表现,被OS识别了!

    (3)软件条件与信号;

    1. #include
    2. unsigned alarm(unsigned seconds);
    3. #include
    4. void abort(void);

     

     也就是人为设定alarm,到时间会自己给自己发送信号。

    abort; 

    (4)调用系统函数发送信号;

     我们可以借这个,模拟写一个kill的封装命令;

           #include
           #include

           int kill(pid_t pid, int sig);

    1. //导入环境变量
    2. export PATH=$PATH:路径

     


     (三)信号保存;

     (1)信号阻塞

    信号的其他概念;

    1.信号递达;实际执行信号的动作

    2.未决;产生~ 递达之间的状态;

    3.阻塞;阻塞某个信号

    ①阻塞与忽略;

    忽略本质是一种处理方式

    阻塞本质是一种 信号递达的反面! 

    (2)内核中的pending 与 block 

    因此,处理信号的过程是;

    发送信号--->修改pending--->合适的时间----->查看block------>执行信号

    (OS)                                                                (阻塞状态下,不可递达)


    (四)信号处理;

    OS决定信号的处理和接收。本质上就是更改进程内 PCB的位图。

    我们不可能操纵内核数据区的 PCB位图。

    但是有一些操作函数供 我们调用;

           #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)sigprocmask

    #include
    int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
    返回值 : 若成功则为 0, 若出错则为 -1

    ①how; 

    SIG_BLOCK

    set里面包含了 我们希望添加到的当前屏蔽信号;

    mask = mask|=set

    SIG_UNBLOCK

    set里 解禁掉 我们屏蔽掉的信号;

    mask=mask & ~ set

    SIG_SETMASK

    设置当前屏蔽的信号值 为set指向的

    set=mask

    (2)sigpending

    #include
    sigpending
    读取当前进程的未决信号集 , 通过 set 参数传出。调用成功则返回 0, 出错则返回 -1 。 

    (3)什么是合适的时候? 

    内核态 ---->用户态


    (五)附加;

    (1)volatile的理解

    我们让 发送二号信号,把flag置位0 中断打印; 

     

    成功中断

     

    加上volatile就是让 编译器不再偷懒,每次去内存里读取数据。

      

    (2)ChLD信号

     


    总结;

    ①信号总共分三个阶段 信号产生、信号保存、信号处理

    ②产生信号的方式很多;系统调用、键盘命令、异常中断(core dump)、软件信号

    ③信号保存本质在于,信号被接收不会被立即处理。因为用户层需要先处理当前优先级高的事情。

    ④在合适的时间(用户态切---->内核态)。

    ⑤pending:是否收到信号 block:信号是否被阻塞 

    ⑥处理信号的过程是;

    OS--->检测pending是否存在----->block是否阻塞---->进行递达;

    ⑦volatile关键字的作用是,保证内存的可见性

    本篇的内容就到此为止;

    感谢你的阅读~

  • 相关阅读:
    BUUCTF刷题十一道(08)
    短剧看剧系统投流版系统搭建,前端uni-app
    《七月集训》(第二十天)——二叉搜索树
    高级算法复习
    Web前端开发涉及的一些技术
    工地安全着装识别系统
    php switch case 多条件使用同一个case
    人体神经元结构示意图,神经细胞内部结构图
    前端面试题:找出任意一个HTML中的所有不重复的标签
    嵌入式led灯效驱动(easy_led)
  • 原文地址:https://blog.csdn.net/RNGWGzZs/article/details/126176597