signalfd介绍
signalfd:传统的处理信号的方式是注册信号处理函数;由于信号是异步发生的,要解决数据的并发访问,可重入问题。signalfd可以将信号抽象为一个文件描述符,当有信号发生时可以对其read,这样可以将信号的监听放到select、poll、epoll等监听队列中。当有事件触发时,有可读事件发生。
signalfd涉及API:
#include <sys/signalfd.h> int signalfd(int fd, const sigset_t *mask, int flags);
参数fd:如果是-1则表示新建一个,不是-1并且是一个合法的signalfd表示向其添加新的信号。
参数mask:信号集合。
参数flag:内核版本2.6.27以后支持SFD_NONBLOCK、SFD_CLOEXEC。
成功返回文件描述符,返回的fd支持以下操作:read、select(poll、epoll)、close。
- 将感兴趣的信号加入到sigset_t中
- 调用signalfd(),把信号集与fd关联起来
- 调用sigprocmask(),把信号集添加进去,避免触发这些信号的默认处理方式
- 阻塞等待信号的发生并读取
- 与传统的处理信号的方式一样,发送多个相同的信号,只处理一次
epoll+signalfd
#include <signal.h> #include <string> #include <sys/epoll.h> #include <sys/signalfd.h> #include <unistd.h> #include<iostream> void signalCallBackFunc(int signalFd) { struct signalfd_siginfo fdsiI; std::cout << "signalCallBackFunc" << std::endl; int s = read(signalFd, &fdsiI, sizeof(struct signalfd_siginfo)); } int main() { int epfd = epoll_create1(0); sigset_t sigintMask; sigemptyset(&sigintMask); sigaddset(&sigintMask, SIGINT); sigprocmask(SIG_BLOCK, &sigintMask, NULL); int sigintfd; sigintfd = signalfd(-1, &sigintMask, 0); struct epoll_event sigintEvent; sigintEvent.data.fd = sigintfd; sigintEvent.events = EPOLLIN; epoll_ctl(epfd, EPOLL_CTL_ADD, sigintfd, &sigintEvent); struct epoll_event events[1024]; while (1) { int n = epoll_wait(epfd, events, 1024, -1); for (int i = 0; i < n; i++) { auto returnfd = events[i].data.fd; signalCallBackFunc(returnfd); } } }