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);
}
相关推荐
A101693307134 分钟前
QT数据库(三):QSqlQuery使用
数据库·qt·oracle
森G35 分钟前
15、QT的容器类---------QT基础
qt
haiyaoyouyou2 小时前
Qt ElaWidgetTools 编译运行示例
开发语言·qt·qt creator·elaframework·mingw_64
不会写DN2 小时前
如何让两个Go程序远程调用?
开发语言·qt·golang
A.A呐17 小时前
【QT第三章】常用控件2
开发语言·qt
笨笨马甲17 小时前
Qt 实现三维坐标系的方法
开发语言·qt
谁动了我的代码?18 小时前
VNC中使用QT的GDB调试,触发断点时与界面窗口交互导致整个VNC冻结
开发语言·qt·svn
肖恭伟18 小时前
QtCreator Linux ubuntu24.04问题集合
linux·windows·qt
vegetablesssss19 小时前
QT国际化翻译
qt
困死,根本不会20 小时前
Qt Designer 基础操作学习笔记
开发语言·笔记·qt·学习·microsoft