signalfd(2)的简介可以通过man手册查看,主要作用就是通过文件描述符就绪的方法来通知信号的到来。
#include
int signalfd(int fd, const sigset_t*mask, intflags);
我有个场景,就是对于信号处理不是一次性决定的,即不是程序一开始就要把信号处理写完,中途可能会添加进去,简化代码思想如下:
int main() {
SignalPoller signalPoller;
signalPoller.signal(SIGUSR1,
[] {
printf("Receive SIGUSR1\n");
});
signalPoller.poll();
signalPoller.signal(SIGUSR2,
[] {
printf("Receive SIGUSR2\n");
});
signalPoller.poll();
}
在第一次poll之前先设置SIGUSR1,然后在poll完之后再设置SIGUSR2,再poll一次。
连续发两个SIGUSR1,正常。
先发SIGUSR1,再发SIGUSR2,正常。
第一次发SIGUSR2,进程退出,因为第一次poll时没有设置处理SIGUSR2,而收到SIGUSR2信号的默认动作时终止进程,所以第二次发送SIGUSR2时,进程已退出。
详细代码(没有写取消信号处理的代码,只是简单演示):
#include
#include
#include
#include
#include
#include
#include
class Signal {
using SignalCallback = std::function<void()>;
using SignalMap = std::map<int, SignalCallback>;
public:
Signal() {
sigemptyset(&mask_);
sfd_ = ::signalfd(-1, &mask_, SFD_NONBLOCK|SFD_CLOEXEC);
}
Signal(const Signal&) = delete;
Signal& operator=(const Signal&) = delete;
void signal(int signo, const SignalCallback& callback)
{ signal(signo, SignalCallback(callback)); }
void signal(int signo, SignalCallback&& callback);
int signalfd() const noexcept { return sfd_; }
void handleRead();
private:
sigset_t mask_;
int sfd_;
SignalMap signalMap_;
};
void Signal::signal(int signo, SignalCallback&& callback) {
sigaddset(&mask_, signo);
sigprocmask(SIG_BLOCK, &mask_, NULL); // sigprocmask是必要的
signalMap_[signo] = std::move(callback);
::signalfd(sfd_, &mask_, SFD_NONBLOCK|SFD_CLOEXEC);
}
void Signal::handleRead() {
struct signalfd_siginfo sigInfo;
int r = ::read(sfd_, &sigInfo, sizeof(sigInfo));
assert(r==sizeof(sigInfo));
auto iter = signalMap_.find(sigInfo.ssi_signo);
if (iter != signalMap_.end()) {
(iter->second)();
}
}
class SignalPoller {
using SignalCallback = std::function<void()>;
public:
SignalPoller()
: signal_() {
pfd_.fd = signal_.signalfd();
pfd_.events = POLLIN;
}
SignalPoller(const SignalPoller&) = delete;
SignalPoller& operator=(const SignalPoller&) = delete;
void poll();
void signal(int signo, const SignalCallback& callback)
{ signal(signo, SignalCallback(callback)); }
void signal(int signo, SignalCallback&& callback);
private:
Signal signal_;
struct pollfd pfd_;
};
void SignalPoller::signal(int signo, SignalCallback&& callback) {
signal_.signal(signo, std::move(callback));
}
void SignalPoller::poll() {
int r = ::poll(&pfd_, 1, -1);
assert(r==1);
if (pfd_.revents & POLLIN)
signal_.handleRead();
}