linux信号的处理总结

大耗子 2020年03月23日 187次浏览

文章链接:https://codemouse.online/archives/2020-03-23190627

发送信号

  • kill命令

    指令格式: kill -signum pid

  • kill 函数

    int kill(pid,signum);
    pid>0 发给pid进程
    pid=0 发给当前进程组的所有进程
    pid=-1 发送给所有进程
    pid<0 发送给|PID|所对应的组上

    发送给自己:int kill(getpid(),signum);

  • raise 自举函数

    自举信号,会给自己发送一个信号
    int raise(int sig);

  • sigqueue函数

    类似于kill,但是可以传送参数

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

    union sigval {
    int sival_int;
    void *sival_ptr;
    };

  • alarm 定时函数

    unsigned int alarm(unsigned int seconds);

    用法:

    signal(SIGALRM,自定义函数);
    alarm(2);

  • ualarm 定时函数

    useconds_t ualarm(useconds_t usecs, useconds_t interval);

    useconds为单位,第一个参数为第一次产生时间,第二个参数为间隔产生

  • setitimer 定时器

    int getitimer(int which, struct itimerval *curr_value);
    int setitimer(int which, const struct itimerval *new_value,
    struct itimerval *old_value);
    Linux会给进程提供三个定时器
    ITIMER_REAL:系统真实的时间来计算,发送的信号是SIGALRM。
    ITIMER_VIRTUAL:该进程在用户态下花费的时间来计算,发送的信号是SIGVTALRM。
    ITIMER_PROF:该进程在用户态下和内核态下所费的时间来计算,发送的信号是SIGPROF

    struct itimerval {
    	struct timeval it_interval; /* next value\*/
    	struct timeval it_value;    /* current value */
    };
    struct timeval {
    	time_t      tv_sec;         /* seconds \*/
    	suseconds_t tv_usec;        /* microseconds */
    };
    

安装和捕获信号

  • 自定义捕捉函数

    signal(signum,handler);

  • 忽略信号

    signal(signum,SIG_IGN);

  • 不可捕捉信号

    SIGKILL SIGSTOP 不能够被捕捉

  • sigaction对象

    默认sa_flags = 0就使用单参数函数指针,设置SA_SIGINFO就使用多参数函数指针,重点只有这两个。

    使用该函数使用此对象

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

    sigaction结构体样式:

    struct sigaction 
    {
           void     (*sa_handler)(int); 
           void     (*sa_sigaction)(int, siginfo_t *, void *);
           sigset_t   sa_mask; // 信号屏蔽集合
           int        sa_flags;  //会影响信号接受特殊标志(控制使用哪个函数指针)
           void     (*sa_restorer)(void);// 用处不大,不必考究
    
    };
    

    sa_flags可选值:

    • SA_NOCLDSTOP
      If signum is SIGCHLD, do not receive notification when child processes stop (i.e., when they receive one of SIGSTOP, SIGTSTP, SIGTTIN, or SIGTTOU) or resume (i.e., they receive SIGCONT)
      (see wait(2)). This flag is meaningful only when establishing a handler for SIGCHLD.

    • SA_NOCLDWAIT (since Linux 2.6)
      If signum is SIGCHLD, do not transform children into zombies when they terminate. See also waitpid(2). This flag is meaningful only when establishing a handler for SIGCHLD, or when
      setting that signal's disposition to SIG_DFL.

      If the SA_NOCLDWAIT flag is set when establishing a handler for SIGCHLD, POSIX.1 leaves it unspecified whether a SIGCHLD signal is generated when a child process terminates. On Linux,
      a SIGCHLD signal is generated in this case; on some other implementations, it is not.

    • SA_NODEFER
      Do not prevent the signal from being received from within its own signal handler. This flag is meaningful only when establishing a signal handler. SA_NOMASK is an obsolete, nonstan‐
      dard synonym for this flag.

    • SA_ONSTACK
      Call the signal handler on an alternate signal stack provided by sigaltstack(2). If an alternate stack is not available, the default stack will be used. This flag is meaningful only
      when establishing a signal handler.

    • SA_RESETHAND
      Restore the signal action to the default upon entry to the signal handler. This flag is meaningful only when establishing a signal handler. SA_ONESHOT is an obsolete, nonstandard syn‐
      onym for this flag.

    • SA_RESTART
      Provide behavior compatible with BSD signal semantics by making certain system calls restartable across signals. This flag is meaningful only when establishing a signal handler. See
      signal(7) for a discussion of system call restarting.

    • SA_RESTORER
      Not intended for application use. This flag is used by C libraries to indicate that the sa_restorer field contains the address of a "signal trampoline". See sigreturn(2) for more
      details.

    • SA_SIGINFO (since Linux 2.2)
      The signal handler takes three arguments, not one. In this case, sa_sigaction should be set instead of sa_handler. This flag is meaningful only when establishing a signal handler.

    siginfo_t结构体样式:

    // 多参数函数指针第二参数的结构体
    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) */
    }
    

信号集合函数说明

  • 函数调用

    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 sigpending(sigset_t *set); //返回未决信号集合

    int sigsuspend(const sigset_t *mask); // 阻塞等待,直到遇到该mask集合以外的信号,然后还原之前的信号屏蔽集合

    int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);// 设置信号屏蔽集合

  • 设置信号屏蔽集合

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

    how的参数:

    SIG_BLOCK :将集合中的信号加入到信号掩码中(信号进来会成为未决信号,暂时不处理)
    SIG_UNBLOCK:将集合中的信号从信号掩码中删除
    SIG_SETMASK:设置信号的屏蔽集合(直接覆盖操作)

注意

  • 信号不能做 时间长的,容易死锁的,线程不安全(malloc)的操作。
  • 服务器一定要处理SIGPIPE,SIGINT,SIGCHLD这三个信号。