Llamada a Funciones Qt desde Manejadores de Señales Unix

No puede llamar a funciones Qt desde manejadores de señales Unix. Se aplica la regla POSIX estándar: Sólo puede llamar a funciones async-signal-safe desde manejadores de señales. Vea Acciones de Señal para la lista completa de funciones que puede llamar desde manejadores de señal Unix.

Pero no desesperes, hay una forma de usar manejadores de señales Unix con Qt. La estrategia es hacer que tu manejador de señales Unix haga algo que eventualmente cause que una señal Qt sea emitida, y luego simplemente retornar desde tu manejador de señales Unix. De vuelta en tu programa Qt, esa señal Qt es emitida y luego recibida por tu función de ranura Qt, donde puedes hacer con seguridad cualquier cosa Qt que no se te permitió hacer en el manejador de señales Unix.

Una forma sencilla de hacer que esto suceda es declarar un par de sockets en tu clase para cada señal Unix que quieras manejar. Los pares de sockets se declaran como miembros de datos estáticos. También creas un QSocketNotifier para monitorizar el extremo de lectura de cada par de sockets, declaras tus manejadores de señales Unix como métodos estáticos de la clase, y declaras una función slot correspondiente a cada uno de tus manejadores de señales Unix. En este ejemplo, pretendemos manejar las señales SIGHUP y SIGTERM. Nota: Debería leer las páginas de manual de socketpair(2) y sigaction(2) antes de leer los siguientes fragmentos de código.

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

En el constructor de MyDaemon, usa la función socketpair(2) para inicializar cada par de descriptores de fichero, y luego crea el QSocketNotifier para monitorizar el extremo de lectura de cada par. La señal activated() de cada QSocketNotifier se conecta a la función slot apropiada, que efectivamente convierte la señal Unix a la señal QSocketNotifier::activated().

MyDaemon::MyDaemon(QObject *parent) : QObject(padre) { 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 = nuevo QSocketNotifier(sighupFd[1], QSocketNotifier::Read, this); connect(snHup, &QSocketNotifier::activado, this, &MyDaemon::handleSigHup); snTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this); connect(snTerm, &QSocketNotifier::activado, this, &MyDaemon::handleSigTerm); .. .}

Inicializa los miembros estáticos en el fichero de implementación:

int MyDaemon::sighupFd[2] = {0, 0};
int MyDaemon::sigtermFd[2] = {0, 0};

En algún otro lugar de su código de inicio, instale sus manejadores de señales Unix con 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;
}

En tus manejadores de señales Unix, escribes un byte en el extremo de escritura de un par de sockets y retornas. Esto hará que el QSocketNotifier correspondiente emita su señal activated(), que a su vez hará que se ejecute la función de ranura Qt apropiada.

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

En las funciones de slot conectadas a las señales QSocketNotifier::activated(), leerás el byte. Ahora estás a salvo de vuelta en Qt con tu señal, y puedes hacer todas las cosas de Qt que no podías hacer en el manejador de señales de Unix.

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

© 2026 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.