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);
}
相关推荐
一律清风10 小时前
QT-文件创建时间修改器
c++·qt
不知所云,10 小时前
qt cmake自定义资源目录,手动加载资源(图片, qss文件)
开发语言·qt
Death20011 小时前
Qt 6 相比 Qt 5 的主要提升与更新
开发语言·c++·qt·交互·数据可视化
机器视觉知识推荐、就业指导11 小时前
使用Qt实现实时数据动态绘制的折线图示例
开发语言·qt
Geek之路15 小时前
QT系统学习篇(1)
开发语言·qt·学习
Geek之路1 天前
Qt系统学习篇(6)-QMainWindow
数据库·qt·学习
初阳7851 天前
【Qt】控件概述(2)—— 按钮类控件
开发语言·qt
初阳7851 天前
【Qt】控件概述(3)—— 显示类控件
开发语言·qt
efls1111 天前
Qt_绘图
开发语言·c++·qt
TravisBytes1 天前
在 Qt 项目中使用 spdlog 的全攻略
开发语言·c++·qt