• [10]APUE:信号


    [a] 常用信号

    • SIGABRT  调用 abort 函数时产生此信号,进程异常终止
    • SIGALRM  调用 alarm 或 setitimer 函数超时之后产生
    • SIGCHLD  子进程终止或 stop 时内核向父进程发送此信号
    • SIGFPE  算术异常,如除以 0 或浮点溢出等
    • SIGHUP  终端连接断开时,会话首进程将收到此信号;向守护进程发送此信号使之重新读取其配置文件
    • SIGINT  中断信号,通常由 Ctrl + C 键发出,发送至前端进程组的所有进程
    • SIGQUIT  退出信号,通常由 Ctrl + 键发出,发送至前端进程组的所有进程
    • SIGKILL  终止进程,此信号不能被忽略或捕获
    • SIGSTOP  停止信号,不可被捕获或忽略,可通过发送 SIGCONT 继续运行
    • SIGTSTP  交互式停止信号,可继续
    • SIGCONT  使处于停止状态的进程继续运行
    • SIGTERM  退出信号,退出前进程可以做相应的清理工作
    • SIGTTIN  后端进程试图读控制终端时,终端驱动程序产生此信号,默认 stop 进程
    • SIGTTOU  后端进程试图写控制终端时,产生此信号,通常允许写出
    • SIGIO  异步 I/O 事件
    • SIGPIPE  当管道读进程已终止或 SOCK_STREAM 套接字已不再连接时,执行写操作,将收到此信号
    • SIGSEGV  无效内存引用,SEGV 代表“段违例”,即:segmentation violation
    • SIGURG  紧急情况信号,如网络连接上接到带外的数据时
    • SIGUSR1  用户自定义信号,无默认行为,用于应用程序自订信号处理机制
    • SIGUSR2  同上
    • SIGXCPU  占用 CPU 时间(秒)超过其 soft rlimit 时
    • SIGXFSZ  进程创建的文件超过所允许的软限制

    [b] 关键概念

    • 低速系统调用:可能会使进程永远阻塞的系统调用继承规则:fork 出的子进程继承父进程的信号处理方式,但 exec 之后会将原捕获的信号更改为默认行为,其余不变
    • 中断的系统调用:被 sigaction 中断的调用默认不重启,可以更改其行为;被 signal 中断则默认重启,现代的 signal 函数多由 sigaction 实现
    • 可重入函数:可在信号处理进程与原进程中相互无干涉调用的函数;可重入函数可能会修改 errno 值,应在调用信号处理函数前保存 errno,在调用后恢复
    • 未决信号(pending):已产生但未递送至目标进程的信号,即被阻塞中的信号
    • 信号屏蔽字(signal mask):将被阻塞的信号集

    [c] kill / raise

    #include <signal.h>
    int kill(pid_t pid, int signo)
    int raise(int signo)
    //成功返回 0,出错返回 -1 
    • raise 只能向自身发送信号,raise(signo) 等价于 kill(getpid(), signo)
    • kill 可向权限内的指定进程(signo > 0)、进程组(signo == 0 时指自身所在进程组,signo < -1 时指定其它进程组)、所有进程(signo ==  -1)发送信号

    [d] sigqueue

    #include <signal.h>
    int sigqueue(pid_t pid, int signo, const sigval value) //成功返回 0,出错返回 -1 
    • 配合 sigaction 函数的 SA_SIGINFO 标志及 sa_sigaction 信号处理函数可实现稳健的信号排队,并附带额外的信息 
    • pid 参数只能指定大于 0 的整数,value 参数用于传递额外的信息,其余行为与 kill 函数一致 

    [e] alarm / pause

    #include <unistd.h>
    unsigned int alarm(unsigned int seconds) //返回 0 或之前设置的闹钟剩余秒数
    int pause(void) //返回 -1,errno 设置为 EINTR 
    • 每个进程只能有一个闹钟时间,新的闹钟将取消旧的闹钟并返回旧的闹钟剩余秒数,无旧闹钟返回 0 
    • 信号处理函数必须放置在 alarm 之前 
    • 只有执行了一个信号处理程序并返回后,pause 才返回,之前一直使调用进程挂起

    [f] sigemptyset / sigfillset / sigaddset / sigdelset / sigismember

    #include <signal.h>
    int sigemptyset(sigset_t *set)
    int sigfillset(sigset_t *set)
    int sigaddset(sigset_t *set, int signo)
    int sigdelset(sigset_t *set, int signo)
    //成功返回 0,出错返回 -1
    int sigismember(const sigset_t *set, int signo) //根据是否匹配,返回 1 或 0 
    • sigemptyset 将信号集初始化成不包含任何信号的空集
    • sigfillset 将信号集初始化成包含所有信号的全集 
    • 使用任何 sigset_t 数据类型前,必须使用以上两函数之一进行初始化

    [g] sigprocmask

    #include <signal.h>
    int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oldset) //成功返回 0,出错返回 -1 
    • how 参数的取值:SIG_BLOCK / SIG_UNBLOCK / SIG_SETMASK,分别代表将指定信号集 set 添加至当前屏蔽字中、从当前屏蔽字中清除 set 中的信号、将屏蔽字直接设置为信号集 set
    • 当 set 参数为 NULL 时,how 参数无意义,可以为任意值,通常设为 0
    • oldset 输出旧的信号屏蔽字 

    [h] sigpending

    #include <signal.h>
    int sigpending(sigset_t *set) //成功返回 0,出错返回 -1 
    • 将当前已被屏蔽且未决的信号写入信号集 set  

    [i] signal / sigaction

    #include <signal.h>
    typedef void (*sighandler_t)(int);
    sighandler_t signal(int signo, sighandler_t handler); //成功返回旧的信号处理策略(指针),出错返回 SIG_ERE
    int sigaction(int signo, const struct sigaction *restrict act, struct sigaction *restrict oldact) //成功返回 0,出错返回 -1 
    struct sigaction {
        void    (*sa_handler)(int signo); //flags 中不含 SA_SIGINFO 标志时执行,否则执行 sa_sigaction 函数
        sigset_t    sa_mask; //信号处理函数执行过程中将被临时屏蔽/阻塞的信号
        int    sa_flags; //控制 sigaction 函数的行为方式
        void    (*sa_sigaction)(int signo, siginfo_t *info, void *context);
    }
    
    struct siginfo {
        int    si_signo; //信号编号
        int    si_code; //产生信号的详细原因
        ...
    }
    • 除自定义信号处理函数外,signal 函数中的 handler 参数可取 SIG_IGN / SIG_DFL / SIG_ERE 等三个常量,分别代表忽略信号、默认行为及 signal 进程出错
    • sigaction 结构体中 sa_flags 字段的常用取值:
      • SA_SIGINFO:此标志指示执行 sa_sigaction 信号处理函数,而不是 sa_handler,并对信号处理函数提供了附加信息
      • SA_RESTART:此标志将使被中断的系统调用在信号处理函数返回后自动重启
      • SA_NOCLDWAIT:若信号是 SIG_CHLD,则当进程的子进程终止时,不生成僵死进程,信号处理函数之后调用的 wait 类函数将一直阻塞,直到所有子进程终止,wait 返回 -1 并设置 errno 为ECHILD
    • siginfo_t 数据类型即 siginfo 结构体

    [j] sigsetjmp / siglongjmp

    #include <setjmp.h>
    int sigsetjmp(sigjmp_buf env, int savemask) //若直接调用,返回 0;若从 siglongjmp 返回,返回 siglongjmp 的 val 参数值
    int siglongjmp(sigjmp_buf env, int val) 
    • 若 savemask 非 0,则从 siglongjmp 函数跳回时,恢复原始的信号屏蔽字;其余行为与 setjmp / longjmp 函数一致
    • FreeBSD 环境下与 setjmp / longjmp 行为完全一致 

    [k] sigsuspend

    #include <signal.h>
    int sigsuspend(const sigset_t *sigmask) //返回 -1,errno 设置为 EINTR 
    • 原子操作:设置信号屏蔽字 + 挂起进程,避免了这两步之间存在时间差带来的问题
    • 直至有信号被捕获,sigsuspend 才返回,sigsuspend 返回时,将信号屏蔽字重置为之前的值

    [l] abort

    #include <stdlib.h>
    void abort(void) //无返回值 
    • 终止进程,并产生 SIGABRT 信号
    • 功能类似于 raise(SIGABRT),但调用进程必然终止 

    [m] sleep / nanosleep

    #include <unistd.h>
    unsigned int sleep(unsigned int seconds) //返回 0,或未休眠完的秒数
    #include <time.h>
    int nanosleep(const struct timespec *req, struct timespec *rem) //若休眠完成,返回 0,若被中断或出错返回 -1,剩余的时间写入 rem
    struct timespec {
        time_t    tv_sec; //
        long    tv_nsec; //纳秒
    }
    /*tips:类似的结构体 timeval,常见于 BSD 函数如 gettimeofday 等*/
    struct timeval {
       time_t      tv_sec; //
       suseconds_t tv_usec; //微秒
    • sleep 通常由 nanosleep 实现 

    [n] sys_siglist / strsignal

    extern char *sys_siglist[]
    /*数组下标是信号编号,数组中的元素是指向信号描述(字符串)的指针*/
    #include <string.h>
    char *strsignal(int signo) //返回指向描述该信号的字符串的指针 
    • 用于获取指定信号的字面描述
  • 相关阅读:
    javascript 的原型与原型链的理解
    mysql 复制原理与实践
    mysql 数据库备份的多种方式
    mysql 事务中如果有sql语句出错,会导致自动回滚吗?
    【原】ios下比较完美的单例模式,已验证
    【原/转】ios指令集以及基于指令集的app包压缩策略
    【原】多线程编程中临界区与互斥锁的区别
    【转】Windows的多线程编程,C/C++
    【转】c++中Vector等STL容器的自定义排序
    【转】牛人整理分享的面试知识:操作系统、计算机网络、设计模式、Linux编程,数据结构总结
  • 原文地址:https://www.cnblogs.com/hadex/p/6128437.html
Copyright © 2020-2023  润新知