Aufrufen von Qt-Funktionen aus Unix-Signal-Handlern

Sie können Qt-Funktionen nicht von Unix-Signalhandlern aus aufrufen. Es gilt die Standard-POSIX-Regel: Sie können nur async-signal-safe Funktionen von Signalhandlern aufrufen. Eine vollständige Liste der Funktionen, die Sie von Unix-Signalhandlern aufrufen können, finden Sie unter Signal-Aktionen.

Aber verzweifeln Sie nicht, es gibt eine Möglichkeit, Unix-Signal-Handler mit Qt zu verwenden. Die Strategie besteht darin, Ihren Unix-Signalhandler etwas tun zu lassen, das schließlich ein Qt-Signal auslöst, und dann kehren Sie einfach von Ihrem Unix-Signalhandler zurück. Zurück in Ihrem Qt-Programm wird dieses Qt-Signal ausgegeben und dann von Ihrer Qt-Slot-Funktion empfangen, wo Sie sicher tun können, was auch immer Sie im Unix-Signalhandler nicht tun durften.

Eine einfache Möglichkeit, dies zu erreichen, besteht darin, in Ihrer Klasse ein Socket-Paar für jedes Unix-Signal zu deklarieren, das Sie behandeln wollen. Die Socket-Paare werden als statische Datenelemente deklariert. Sie erstellen auch eine QSocketNotifier, um das Leseende jedes Socket-Paares zu überwachen, deklarieren Ihre Unix-Signal-Handler als statische Klassenmethoden und deklarieren eine Slot-Funktion, die jedem Ihrer Unix-Signal-Handler entspricht. In diesem Beispiel beabsichtigen wir, sowohl die SIGHUP- als auch die SIGTERM-Signale zu behandeln. Hinweis: Sie sollten die Man Pages socketpair(2) und sigaction(2) lesen, bevor Sie sich durch die folgenden Codeschnipsel arbeiten.

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;
};

Verwenden Sie im MyDaemon-Konstruktor die Funktion socketpair(2), um jedes Dateideskriptorpaar zu initialisieren, und erstellen Sie dann die QSocketNotifier, um das Leseende jedes Paares zu überwachen. Das activated()-Signal jedes QSocketNotifier wird mit der entsprechenden Slot-Funktion verbunden, die das Unix-Signal effektiv in das QSocketNotifier::activated()-Signal umwandelt.

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())); ...}

An einer anderen Stelle in Ihrem Startup-Code installieren Sie Ihre Unix-Signal-Handler mit sigaction(2).

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;
}

In Ihren Unix-Signal-Handlern schreiben Sie ein Byte an das schreibende Ende eines Socket-Paares und kehren zurück. Dies veranlasst die entsprechende QSocketNotifier, ihr activated()-Signal auszusenden, was wiederum die Ausführung der entsprechenden Qt-Slot-Funktion bewirkt.

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));
}

In den Slot-Funktionen, die mit den QSocketNotifier::activated() Signalen verbunden sind, lesen Sie das Byte. Jetzt sind Sie mit Ihrem Signal sicher zurück in Qt und können all die Qt-Sachen machen, die Sie im Unix-Signalhandler nicht machen durften.

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);
}

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.