操作系统:10 信号处理

news/2024/10/30 15:32:38/

基本概念:

    1、中断

        当程序接收到消息后中止了当前正在执行的程序,转而执行其他的任务,等其他任务执行完成后可能再返回继续执行,这种执行模式称为中断执行

        分为硬件中断和软件中断

        硬件中断由外设硬件产生的中断,例如键盘、鼠标都可以产生,可以屏蔽

        软件中断是程序执行了中断指令后产生的中断

    2、信号

        信号是一种软件中断,是由操作系统发出的中断信号,被程序接收后执行相应的操作

    3、常见的信号

        kill -l 显示所有信号

        SIGINT (2)  Ctrl+c  终止

        SIGQUIT(3)  Ctrl+\  终止+core(内存映像 内存崩溃)

        SIGFPE(8)   除0\溢出 终止+core

        SIGKILL(9)  用于杀死进程   终止

        SIGSEGV(11) 非法访问内存   终止

    4、不可靠信号和可靠信号

        建立在早期的信号处理机制上的信号(1-31),称为不可靠信号

            不支持排队机制,可能会丢失信号,如果同一个信号连续发送多次,进程可能只接受到了一次

        建立在新的信号处理机制上的信号(34~64),称为可靠信号

            支持排队机制,如果信号连续发送,也不会丢失

    5、信号的来源

        硬件异常:除0、非法访问内存、使用了未定义的指令、总线错误

        软件异常:通过一些命令、函数产生信号

    6、信号的处理

        ① 忽略

        ② 终止进程

        ③ 终止进程+产生core文件

        ④ 捕获并处理信号(在信号发出前,向内核注册一个信号处理函数,绑定该信号与信号处理函数,当信号发出后,会执行信号处理函数)

信号捕获和注册

    typedef void (*sighandler_t)(int);

    注意:信号处理函数的格式

        参数int表示是导致执行该函数的信号的ID

    sighandler_t signal(int signum, sighandler_t handler);

    功能:向内核提出绑定一个信号处理函数

    signum:信号编号

    handler:信号处理函数函数名

        还可以写成:

        SIG_IGN 忽略处理

        SIG_DFL 按默认方式处理

    返回值:

        返回绑定之前的信号处理函数指针,一般用于记录还原

    注意:有个别操作系统通过signal注册的信号只能执行一次信号处理函数,如果想要持续有效,可以在信号处理函数中再重新signal注册一次

    注意:虽然有些信号可以捕获,但是产生该信号的错误原因(段错误\除0)依旧还在,如果信号处理函数执行完后不终止进程,就会返回到产生错误的位置,导致死循环,正确的操作是保存数据后,终止进程

信号发出的方式

1、键盘:

            Ctrl+c

            Ctrl+\

            Ctrl+z  暂停\挂起  fg命令恢复最后暂停的进程

2、错误:

            非法访问内存

            除0

            硬件故障、总线错误

            (捕获后,要及时终止进程)

3、命令:

            kill -信号id 进程号

            killall -信号id 进程名

                发送信号给所有名字为同名的进程

4、函数:

        int kill(pid_t pid, int sig);

        功能:向指定的进程发送信号

        pid:进程号

        sig:信号

    int raise(int sig);

        功能:给进程自己发送信号

    void abort(void);

        功能:给进程自己发送SIGABRT(6)信号

    unsigned int alarm(unsigned int seconds);

        功能:让内核在seconds秒后向进程自己发送SIGALRM(14)信号

        返回值:上一次调用后,闹钟剩余的秒数

        注意:如果重复调用该函数,只会覆盖之前的设置时间,而不会产生多次闹钟信号

进程休眠与信号

    int pause(void);

    功能:让调用者进程进入休眠态,直到遇到信号后就会唤醒

    返回值:要么一直不返回,要么信号来了返回-1

    unsigned int sleep(unsigned int seconds);

    功能:让调用者进程进入休眠指定秒数,当遇到信号时会提前返回

    返回值:还在休眠中不返回,唤醒后返回剩余睡眠秒数

信号集与信号屏蔽(阻塞):

1、信号集:

        是一种数据类型,定义出来的变量可以存储表示多个信号

2、相关函数:

    int sigemptyset(sigset_t *set);

    功能:清空信号集

    int sigfillset(sigset_t *set);

    功能:填满信号集

    int sigaddset(sigset_t *set, int signum);

    功能:向信号集中添加某个信号

    int sigdelset(sigset_t *set, int signum);

    功能:从信号集中删除某个信号

    int sigismember(const sigset_t *set, int signum);

    功能:测试查看信号集中是否有某个信号

    返回值:

        0   不存在

        1   存在

        -1  信号非法

3 信号屏蔽

        当程序执行一些特殊操作时是不适合处理信号的,此时可以让内核先屏蔽信号处理,等特殊操作完成后再继续处理信号

        当信号产生时,内核会在该进程中的信号维护表中为该进程标记此信号,一旦完成标记进程就开始响应信号,此过程称为递送

        从信号产生到完成递送过程有一个时间间隔,处于这个时间间隔的信号状态叫未决

        信号屏蔽就是让信号处于未决状态,暂停递送,当屏蔽解除时再继续进行递送

        每个进程都有一个信号集用于存储要屏蔽的信号,称为信号屏蔽集

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

        功能:设置信号屏蔽集

        how:信号屏蔽的方式

            SIG_BLOCK

                把set中信号添加到信号屏蔽集中

            SIG_UNBLOCK

                从信号屏蔽集中删除set中的信号

            SIG_SETMASK

                把信号屏蔽集中的信号全部替换成set中的信号

        set:准备设置的信号集

        old-set:获取旧的信号屏蔽集

4 附带信息的高级信号处理

    int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

    功能:向内核注册一个信号处理函数,相当于signal的升级版

    signum:要捕获的信号

    act:

        struct sigaction {

            void  (*sa_handler)(int);//不附带数据的信号处理函数

            void  (*sa_sigaction)(int,siginfo_t *,void *);//  附带附加数据的信号处理函数

            sigset_t sa_mask;   // 信号屏蔽集,在该函数执行时,默认会屏蔽当前信号,如果想要屏蔽其他信号,可以向sa_mask中增加信号

            int      sa_flags;  // 绑定信号的标志位

                SA_SIGINFO  使用第二个函数指针进行绑定

                SA_NODEFER  在信号绑定中不要屏蔽该信号

                SA_RESETHAND 在该信号处理方式执行完后,还原回默认的处理方式

                SA_RESTART 系统调用一旦被该绑定的信号打断后,自动重启系统调用

            void  (*sa_restorer)(void);//保留项 NULL

        };

    siginfo_t {

        int      si_signo;     /* Signal number */

        int      si_errno;     /* An errno value */

        int      si_code;      /* Signal code */

        int      si_trapno;    //

        pid_t    si_pid;       /* Sending process ID */

        uid_t    si_uid;       /* Real user ID of sending process */

        int      si_status;    /* Exit value or signal */

        clock_t  si_utime;     /* User time consumed */

        clock_t  si_stime;     /* System time consumed */

        sigval_t si_value;     /* Signal value */

        int      si_int;       /* POSIX.1b signal */

        void    *si_ptr;       /* POSIX.1b signal */

        int      si_overrun;   /* Timer overrun count;

                                    POSIX.1b timers */

        int      si_timerid;   /* Timer ID; POSIX.1b timers */

        void    *si_addr;      /* Memory location which caused fault */

        long     si_band;      //

        int      si_fd;        /* File descriptor */

        short    si_addr_lsb;  /*/

        void    *si_call_addr; /* Address of system call instruction

                                    (since Linux 3.5) */

        int      si_syscall;   /* Number of attempted system call

                                    (since Linux 3.5) */

    }

     int sigqueue(pid_t pid,int sig,const union sigval value);

    功能:向指定的进程发送附带有数据的信号

    pid:进程号

    sig:信号ID

    value:要附带的数据

        union sigval {

            int   sival_int;    //整数

            void *sival_ptr;    //指针

        };

    注意:通过这样附带信息的操作,可以让不同的进程进行数据通信

5 定时器

    int getitimer(int which,struct itimerval *curr_value);

    功能:获取当前定时方案

    which:选择计时器  

        ITIMER_REAL     真实计时器 程序的总运行时间SIGALRM

        ITIMER_VIRTUAL  虚拟计时器 用户态的运行时间                              SIGVTALRM    

        ITIMER_PROF     实际计时器 用户态+内核态的运行时间                              SIGPROF

        真实计时器 = 实际计时器+切换时间+休眠时间

    int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value);

    功能:设置新的定时方案

     struct itimerval {

        struct timeval it_interval; // 每次计时器产生信号的时间间隔

        struct timeval it_value;   //第一次信号产生的时间

    };

    struct timeval {

        time_t      tv_sec;         // 秒

        suseconds_t tv_usec;        // 微秒

    };


http://www.ppmy.cn/news/65845.html

相关文章

花菁染料CY5.5标记活性脂 Cy5.5-NHS

Cy5.5 NHS ester用于染色蛋白质、标记DNA、标记细胞表面抗原、标记抗体和其他生物分子。Cy5.5 NHS ester还可以用于分子影像学,可以追踪细胞内的变化。它还可以用于荧光免疫检测,以检测细胞表面抗原和抗体。 产品名称:五甲川花菁染料CY5.5标记…

商用密码应用安全性测评机构资质流程

商用密码应用安全性测评机构(简称密评机构)资质建设相关指导性材料包括: 1、《商用密码应用安全性测评机构能力要求》 2、《商用密码应用安全性测评机构能力评审实施细则(试行)》 3、《商用密码应用安全性测评机构管理…

三流面试聊技术,二流面试聊框架,一流面试…

前言 本文是为了帮大家快速回顾了软件测试中知识点,这套面试手册涵盖了诸多软件测试技术栈的面试题和答案,相信可以帮助大家在最短的时间内用作面试复习,能达到事半功倍效果。 本来想将文件上传到github上,但由于文件太大有的都…

如何解决App Store Connect中的“90704”图标错误的问题

如何解决App Store Connect中的“90704”图标错误的问题 在iOS应用开发中,我们需要将应用程序打包成ipa包并上传到App Store Connect 进行审核。相信很多开发者应该都有遇到“90704”错误。这会导致上传失败,通常 是因为我们上传的应用程序图标不符合…

web前端Javascript—7道关于前端的面试题

本文主要是web前端Javascript—的面试题,附上相关问题以及解决答案,希望对大家web前端Javascript闭包的学习有所帮助。 每个JavaScript 程序员都必须知道闭包是什么。在 JavaScript 面试中,你很可能会被问到的问题 以下是 7 个有关 JavaScr…

带头双向循环链表原来这么简单?

☃️个人主页:fighting小泽 🌸作者简介:目前正在学习C语言和数据结构 🌼博客专栏:数据结构 🏵️欢迎关注:评论👊🏻点赞👍🏻留言💪&…

[oeasy]python0050_动态类型_静态类型_编译_运行

动态类型_静态类型 回忆上次内容 上次了解了 帮助文档的 生成 开头的三引号注释 可以生成 帮助文档文档 可以写成网页 python3 本身 也有 在线的帮助手册 目前的程序 提高了 可读性 有什么方法 可以让程序 更可读么?🤔 变量名 首先 在变量名上想办…

LeetCode 452 用最少数量的箭引爆气球

题目: 有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i] [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在…