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);
}
相关推荐
Morwit2 小时前
QML组件之间的通信方案(暴露子组件)
c++·qt·职场和发展
金色熊族6 小时前
解析QTransform的用法
qt
追烽少年x8 小时前
Qt多线程编程:QThread与QtConcurrent的对比与应用
qt
小短腿的代码世界1 天前
Qt实时盈亏计算深度解析:从持仓数据到动态盈亏展示
开发语言·qt
Python私教1 天前
GenericAgent PySide6 桌面应用深度解析:悬浮按钮 + 聊天面板的原生 Qt 方案
开发语言·数据库·qt
用户805533698031 天前
现代Qt开发教程(新手篇)1.11——定时器
c++·qt
小短腿的代码世界1 天前
Qt券商接口封装深度解析:统一API设计与多源适配
开发语言·qt·单元测试
T0uken1 天前
基于 vcpkg 与 LLVM-MinGW 的 Qt6 静态链接开发方案
c++·windows·qt
Ulyanov1 天前
《现代 Python 桌面应用架构实战:PySide6 + QML 从入门到工程化》 开发环境搭建与工具链极简主义 —— 拒绝臃肿,构建工业级基座
开发语言·python·qt·ui·架构·系统仿真
(Charon)1 天前
【C++/Qt】Qt 实现 MQTT 测试工具:连接 Broker、订阅主题与发布消息
开发语言·c++·qt