signalfd的用法

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一次。

测试结果:
signalfd的用法_第1张图片

连续发两个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();
}

你可能感兴趣的:(c++)