Linux之信号

Eyu / 2023-08-15 / 原文

信号集类型sigset_t

定义

typedef struct
{
    unsigned long sig[_NSIG_WORDS];
} sigset_t

相关函数

#include <signal.h>

sigemptyset(sigset_t *set)			//初始化由set指定的信号集,信号集里面的所有信号被清空
sigfillset(sigset_t *set)			//调用该函数后,set指向的信号集中将包含linux支持的64种信号
sigaddset(sigset_t *set, int signum)		//在set指向的信号集中加入signum信号;
sigdelset(sigset_t *set, int signum)		//在set指向的信号集中删除signum信号;
sigismember(const sigset_t *set, int signum)	//判定信号signum是否在set指向的信号集中。

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_handler:函数指针,指向信号处理函数。默认使用此函数处理信号
  • sa_sigaction:同样是信号处理函数,有三个参数,可以获得关于信号更详细的信息。可以通过参数三使用此函数处理信号。即参数一和参数二是二选一的。
  • sa_mask:信号处理函数执行期间需要被屏蔽的信号
  • sa_flags:指定信号处理的行为
    • SA_RESTART,使被信号打断的系统调用自动重新发起
    • SA_NOCLDSTOP,使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD 信号
    • SA_NOCLDWAIT,使父进程在它的子进程退出时不会收到 SIGCHLD 信号,这时子进程如果退出也不会成为僵尸进程
    • SA_NODEFER,使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号
    • SA_RESETHAND,信号处理之后重新设置为默认的处理方式
    • SA_SIGINFO,使用 sa_sigaction 而不是 sa_handler 作为信号处理函数
  • sa_restorer:废弃不使用

Linux下信号处理机制

Linux下的信号采用的异步处理机制,当进程收到信号时,操作系统会中断进程当前的正常流程,转而进入信号处理函数执行操作,完成后再返回中断的地方继续执行,且信号处理期间系统不会再次触发它,即处理期间如果有同类型的信号发来会被屏蔽。所以我们希望信号处理函数执行快、尽可能少错过信号。
一般的解决方案是,信号处理函数用于通知主循环发生信号,具体的处理逻辑放在主循环中。

统一事件源

信号处理函数使用管道将信号传递给主循环,信号处理函数往管道的写端写入信号值,主循环则从管道的读端读出信号值,使用I/O复用(select、poll、epoll)系统调用来监听管道读端的可读事件,这样信号事件与其他文件描述符都可以通过epoll来监测,从而实现统一处理

使用管道通信

在linux下,使用socketpair函数能够创建一对套接字进行通信

#include <sys/types.h>
#include <sys/socket.h>
int socketpair(int domain, int type, int protocol, int sv[2]);
  • domain:协议族
  • type:协议。SOCK_STREAM(基于TCP)或者SOCK_DGRAM(基于UDP)
  • protocol:类型,只能为0
  • sv[2]:即管道两端,均可进行读写操作
  • 返回值:成功为0,失败为-1