4 信号处理

发布于:2022-12-26 ⋅ 阅读:(348) ⋅ 点赞:(0)

二十一、信号处理

    基本概念

        1.中断

            当程序接收到消息后中断当前正在执行的程序,转而执行其它任务,

            等其它任务执行完成后在返回

            分为硬件中断和软件中断

        2.信号

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

        3.常见的信号

            命令: kill -l 查看所有信号

            SIGINT(2)       Ctrl+c             终止

            SIGQUIT(3)      Ctrl+\             终止\core

            SIGFPF(8)       除零               终止\core

            SIGKILL(9)      终止信号            终止        不能捕获、忽略

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

        4.不可靠信号和可靠信号

            不可靠信号:建立在早期(1~31)的信息处理机制上的信息

                不支持排队(可能会丢失信号),如果同一个信号连续产生多次,进程可能值响应一次

            可靠信号:建立在新(34~64)的信息处理机制上的信息

                支持排队    信号会一一响应

        5.信号的来源

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

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

        6.信号的处理方式

            1.忽略

            2.终止进程

            3.终止进程并产生core文件(记录内存映像)

            4.停止

            5.继续

            6.捕获并处理 (在信号发生前,先向内核注册一个函数,当信号来临时系统自动执行函数)

二十二、信号捕获

    #include <signal.h>

    typedef void (*sighandler_t)(int);

    sighandler_t signal(int signum, sighandler_t handler);

    功能:向内核注册一个信号处理函数

    signum:信息编号

    handler:函数指针

        也可使用以下参数:

        SIG_IGN     忽略

        SIG_DFL     按默认方式处理

    返回值:之前的信号处理方式

    注意:

    1. 9和19 信号不能被捕获和被忽略处理

    2.当信号处理完后,可能会返回产生信号的代码会继续运行,如果我们捕获段错误、

      算术异常等信号可能会产生死循环,正确的处理段错误、算术异常循环应该是备份数据并直接结束程序

    3.有些系统通过signal注册的信号处理函数只能执行一次,如果想要持续有效,

      可以信号处理函数中再重新注册一次

    4.子进程会继承父进程的信号处理方式,但是通过exec系列函数创建的子进程,会恢复默认的信号处理方式

           

信号的发送发送

    1.键盘

        Ctrl + c

        Ctrl + \

        Ctrl + z 暂停  fg 继续

    2.错误  除零、非法访问内存、总线错误

    3.命令  

        kill -信号编号 进程号  向指定的进程发送信号

        killall -信号编号  进程名   可以给同名进程发送同一个信号

    4.函数

        #include <sys/types.h>

        #include <signal.h>

        int kill(pid_t pid, int sig);

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

        pid:进程号

        sig:信号编号

        #include <signal.h>

        int raise(int sig);

        功能:向自己发送信号

        #include <stdlib.h>

        void abort(void);

        功能:向进程自己发送SIGABRT信号

        #include <unistd.h>

        unsigned int alarm(unsigned int seconds);

        功能:让内核在seconds秒后向进程发送SIGALRM信号

        返回值:上一次alarm设置的剩余的秒数



 

二十三、进程休眠信号

    int pause(void);

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

    返回值:要么吧返回在休眠,要么唤醒后返回-1

    相当于没有时间限制的sheep

    #include <unistd.h>

    unsigned int sleep(unsigned int seconds);

    功能:让调用者进入休眠直到的秒数,当遇到信号时,会提前唤醒返回

    返回值:剩余的休眠时间

二十四、信号集合信号堵塞

    信号集:是一种数据类型,定义的变量可以存储多个信号

        sigset_t 128位的二进制数(每一位斗代表了一种信号)

        相关函数:

        int num = 0;

        #include <signal.h>

        int sigemptyset(sigset_t *set);

        功能:清空信号集

        int sigfillset(sigset_t *set);

        功能:填满信号集

        int sigaddset(sigset_t *set, int signum);

        功能:向信号集set中添加signum

        int sigdelset(sigset_t *set, int signum);

        功能:向信号集set中删除signum

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

        功能:测试信号集中是否存在signum

        返回值:

            0   不存在

            1   存在

            -1  signum信号非法

    信号阻塞:

        当程序执行到一些特殊操作时,不适合处理信号,此时可以让内核先屏蔽信号,

        等操作执行完成后再解除屏蔽重新发送信号;

        当信号产生时,内核会在其维护的信号表中为对应的进程设置与该信号对应的标记,这个过程叫做递送;

        从信号产生到完成递送有个时间间隔,处于这个间隔的信号状态称为未决;

        信号屏蔽/阻塞就是让被屏蔽的信号先处于未决状态,暂停递送,当屏蔽解除时,继续递送;

        #include <signal.h>

        int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

        功能:设置要屏蔽的信号、这些信号时存储在信号集里面的

        how:信号屏蔽的方式

            SIG_BLOCK       把set中的信号添加到要屏蔽的信号集里

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

            SIG_SETMASK     把set替换之前的信号屏蔽集

        set:准备好的信号集

        oldset:获取旧的信号集

二十五、附带信号的信号处理

    #include <signal.h>

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

    功能:向内核注册一个信号处理函数

    signum:要捕获的信号编号

    act:设置要处理的动作

    oldact:获取原来的动作

    struct sigaction

    {

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

        void (*sa_sigaction)(int, siginfo_t *, void *);//附带其他信息的信号处理函数

        sigset_t sa_mask;//信号屏蔽集

        int sa_flags; //  信号处理动作标志

        SA_NODEFER  在信号处理过程中不要屏蔽当前信号

        SA_SIGINFO  使用 sa_sigaction 函数指针

        void (*sa_restorer)(void);//保留函数

    };

    siginfo_t

    {

        int si_signo;      /* Signal number */

        int si_errno;      /* An errno value */

        int si_code;       /* Signal code */

        int si_trapno;     /* Trap number that caused

                              hardware-generated signal

                              (unused on most architectures) */

        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;      /* Band event (was int in

                              glibc 2.3.2 and earlier) */

        int si_fd;         /* File descriptor */

        short si_addr_lsb; /* Least significant bit of address

                              (since Linux 2.6.32) */

        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) */

        unsigned int si_arch; /* Architecture of attempted system call

                                 (since Linux 3.5) */

    }

    #include <signal.h>

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

    功能:向指定进程发送信号并附加信息一起发送

    value:附加的信息

    union sigval

    {

        int sival_int;      //整数

        void *sival_ptr;    //指针

    };

二十六、定时器

    #include <sys/time.h>

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

    功能:获取当时的定时方案

    which:选择使用的计时器

        ITIMER_REAL         真实计时器,程序总的计时        SIGALRM(14)

        ITIMER_VIRTUAL      虚拟计时器,用户态的计时        SIGVTALRM(26)

        ITIMER_PROF         实际计时器,用户态+内核态计时   SIGPROF(27)

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

    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; /* 设置微秒 */

    };

本文含有隐藏内容,请 开通VIP 后查看