QT处理Unix信号

从Unix信号处理程序中调用Qt函数

你不能从Unix信号处理程序中调用Qt函数。适用于标准POSIX规则:只能从信号处理程序调用异步信号安全的函数。有关可以从Unix信号处理程序调用的函数的完整列表,请参阅Signal Actions

但不要绝望,有一种方法可以在Qt中使用Unix信号处理程序。策略是让Unix信号处理程序做一些事情,最终导致Qt信号被发出,然后您只需从Unix信号处理程序返回。回到你的Qt程序,Qt信号被发射,然后被Qt插槽函数接收,在这里你可以安全地做任何Qt的事情你在Unix信号处理程序中不允许做的事情。

一种简单的方法是**在类中为要处理的每个Unix信号声明一个套接字对。套接字对被声明为静态数据成员。还创建了一个QSocketNotifier来监视每个套接字对的读取结束,将Unix信号处理程序声明为静态类方法,并声明对应于每个Unix信号处理程序的插槽函数。**在这个例子中,我们打算同时处理SIGHUP和SIGTERM信号。注意:在阅读下面的代码片段之前,你应该先阅读socketpair(2)和sigaction(2)手册页。

cpp 复制代码
class MyDaemon : public QObject
{
    Q_OBJECT

  public:
    MyDaemon(QObject *parent = 0);
    ~MyDaemon();

    // Unix signal handlers.
    static void hupSignalHandler(int unused);
    static void termSignalHandler(int unused);

  public slots:
    // Qt signal handlers.
    void handleSigHup();
    void handleSigTerm();

  private:
    static int sighupFd[2];
    static int sigtermFd[2];

    QSocketNotifier *snHup;
    QSocketNotifier *snTerm;
};

在MyDaemon构造函数中,使用socketpair(2)函数初始化每个文件描述符对,然后创建QSocketNotifier来监视每个文件描述符对的读端。每个QSocketNotifier的activated()信号连接到相应的插槽函数,该函数有效地将Unix信号转换为QSocketNotifier::activated()信号。

cpp 复制代码
MyDaemon::MyDaemon(QObject *parent)
        : QObject(parent)
{
    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sighupFd))
       qFatal("Couldn't create HUP socketpair");

    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigtermFd))
       qFatal("Couldn't create TERM socketpair");
    snHup = new QSocketNotifier(sighupFd[1], QSocketNotifier::Read, this);
    connect(snHup, SIGNAL(activated(QSocketDescriptor)), this, SLOT(handleSigHup()));
    snTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this);
    connect(snTerm, SIGNAL(activated(QSocketDescriptor)), this, SLOT(handleSigTerm()));

    ...
}

在启动代码的其他地方,使用sigaction(2)安装Unix信号处理程序。

cpp 复制代码
static int setup_unix_signal_handlers()
{
    struct sigaction hup, term;

    hup.sa_handler = MyDaemon::hupSignalHandler;
    sigemptyset(&hup.sa_mask);
    hup.sa_flags = 0;
    hup.sa_flags |= SA_RESTART;

    if (sigaction(SIGHUP, &hup, 0))
       return 1;

    term.sa_handler = MyDaemon::termSignalHandler;
    sigemptyset(&term.sa_mask);
    term.sa_flags = 0;
    term.sa_flags |= SA_RESTART;

    if (sigaction(SIGTERM, &term, 0))
       return 2;

    return 0;
}

在Unix信号处理程序中,将一个字节写入套接字对的写端并返回。这将导致相应的QSocketNotifier发出它的activated()信号,进而导致相应的Qt槽函数运行。

cpp 复制代码
void MyDaemon::hupSignalHandler(int)
{
    char a = 1;
    ::write(sighupFd[0], &a, sizeof(a));
}

void MyDaemon::termSignalHandler(int)
{
    char a = 1;
    ::write(sigtermFd[0], &a, sizeof(a));
}

在连接到qsocketnotification::activated()信号的槽位函数中,读取字节。现在你安全地回到了Qt中,你的信号,你可以做所有Qt的东西,你不被允许做在Unix信号处理程序。

cpp 复制代码
void MyDaemon::handleSigTerm()
{
    snTerm->setEnabled(false);
    char tmp;
    ::read(sigtermFd[1], &tmp, sizeof(tmp));

    // do Qt stuff

    snTerm->setEnabled(true);
}

void MyDaemon::handleSigHup()
{
    snHup->setEnabled(false);
    char tmp;
    ::read(sighupFd[1], &tmp, sizeof(tmp));

    // do Qt stuff

    snHup->setEnabled(true);
}
相关推荐
颜*鸣&空8 小时前
QT实现串口通信+VSPD+串口调试工具
开发语言·qt
颜*鸣&空13 小时前
QT程序实现串口通信案例
开发语言·qt
Main. 2413 小时前
从0到1学习Qt -- 常见控件之显示类控件
qt·学习
qq_4017004119 小时前
Qt中事件循环与并发机制的协同工作
qt
qq_401700412 天前
Qt Positioning 模块访问设备地理位置信息
开发语言·qt
闫有尽意无琼2 天前
银河麒麟v11 arm编译Qt creator8.0.2报错
开发语言·qt
lqj_本人2 天前
鸿蒙Qt触控疑云:事件传递丢失与坐标偏移修复
qt·华为·harmonyos
_OP_CHEN2 天前
从零开始的Qt开发指南:(五)Qt 常用控件之 QWidget(上):解锁 Qt 界面开发的核心基石
开发语言·c++·qt·前端开发·qwidget·gui开发·qt常用控件
happyjoey2172 天前
使用Qt自带的Maintenance Tool将Qt6.9升级为QT6.10
开发语言·qt
lqj_本人2 天前
鸿蒙Qt生命周期:后台被杀后的数据自救
qt·华为·harmonyos