信号

Posted on 2023-02-27 11:23  lyc2002  阅读(18)  评论(0编辑  收藏  举报

介绍

#include <signal.h>

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

功能:为一个信号设置处理函数

参数:

  • signum:要捕获的信号类型

  • act:新的信号处理方式

    struct sigaction {
        void     (*sa_handler)(int); // 指定信号处理函数
        void     (*sa_sigaction)(int, siginfo_t *, void *);
        sigset_t   sa_mask; // 临时在进程原有信号掩码的基础上增加信号掩码,指定哪些信号不能发送给本进程,当前处理函数执行完毕,临时屏蔽自动解除
        /*
        	sigset_t 和 fd_set 类似,通过以下函数来设置、修改、删除和查询信号集
            
            #include <signal.h>
    
            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);
        */
        int        sa_flags; // 设置程序收到信号时的行为
        void     (*sa_restorer)(void); // 已经过时,最好不使用
    };
    
  • oldact:信号先前的处理方式

返回值:

  • 成功返回 0
  • 失败返回 -1,并设置 errno

简单使用

void addsig(int sig, void handler(int), bool restart = true)
{
    strcut sigaction sa;
    memset(sa, '\0', sizeof(sa));
    sa.sa_handler = handler;
    if (restart) {
        /* 如果程序在执行处于阻塞状态的系统调用时接收到信号,
           并且我们为该信号设置了信号处理函数,则默认情况下系统调用将被中断,
           并且 errno 被设置为 EINTR。可以使用 sigaction 函数
           为信号设置 SA_RESTART 标志以自动重启被信号中断的系统调用。
        */
        sa.sa_flag |= SA_RESTART;
    }
    sigfillset(&sa.sa_mask);
    int ret = sigaction(sig, &sa, nullptr);
    assert(ret != -1);
    (void)ret;
}

注意事项

  • 除了用户自定义信号处理函数外,bits/signum.h 头文件中还定义了信号的两种其他处理方式。
#include <bits/signum.h>
#define SIG_DFL ((__sighandler_t) 0) // 表示使用信号的默认处理方式
#define SIG_IGN ((__sighandler_t) 1) // 表示忽略目标信号
  • 默认情况下,往一个读端关闭的管道或 socket 连接中写数据将引发 SIGPIPE 信号。我们需要在代码中捕获并处理该信号,或者至少忽略它,因为程序接收到该信号的默认行为是结束进程,而我们不希望因为错误的写操作导致程序退出。