Appel de fonctions Qt à partir de gestionnaires de signaux Unix
Vous ne pouvez pas appeler de fonctions Qt depuis des gestionnaires de signaux Unix. La règle POSIX standard s'applique : vous ne pouvez appeler que des fonctions async-signal-safe depuis des gestionnaires de signaux. Reportez-vous à la section Actions sur les signaux pour obtenir la liste complète des fonctions que vous pouvez appeler depuis des gestionnaires de signaux Unix.
Mais ne désespérez pas, il existe un moyen d’utiliser les gestionnaires de signaux Unix avec Qt. La stratégie consiste à faire en sorte que votre gestionnaire de signaux Unix effectue une action qui finira par provoquer l’émission d’un signal Qt, puis à simplement quitter votre gestionnaire de signaux Unix. De retour dans votre programme Qt, ce signal Qt est émis puis reçu par votre fonction slot Qt, où vous pouvez effectuer en toute sécurité toutes les opérations Qt que vous n’étiez pas autorisé à effectuer dans le gestionnaire de signaux Unix.
Une méthode simple pour y parvenir consiste à déclarer une paire de sockets dans votre classe pour chaque signal Unix que vous souhaitez gérer. Les paires de sockets sont déclarées comme membres de données statiques. Vous créez également une instance de ` QSocketNotifier ` pour surveiller le côté lecture de chaque paire de sockets, vous déclarez vos gestionnaires de signaux Unix comme des méthodes de classe statiques, et vous déclarez une fonction de slot correspondant à chacun de vos gestionnaires de signaux Unix. Dans cet exemple, nous souhaitons gérer à la fois les signaux `SIGHUP` et `SIGTERM`. Remarque : nous vous recommandons de consulter les pages de manuel socketpair(2) et sigaction(2) avant de vous plonger dans les extraits de code suivants.
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;
};Dans le constructeur de MyDaemon, utilisez la fonction socketpair(2) pour initialiser chaque paire de descripteurs de fichiers, puis créez l’ QSocketNotifier e pour surveiller l’extrémité de lecture de chaque paire. Le signal activated() de chaque QSocketNotifier est relié à la fonction de slot appropriée, ce qui convertit effectivement le signal Unix en signal QSocketNotifier::activated().
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, &QSocketNotifier::activated, this, &MyDaemon::handleSigHup);
snTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this);
connect(snTerm, &QSocketNotifier::activated, this, &MyDaemon::handleSigTerm);
...
}Initialisez les membres statiques dans le fichier d'implémentation :
int MyDaemon::sighupFd[2] = {0, 0};
int MyDaemon::sigtermFd[2] = {0, 0};Ailleurs dans votre code de démarrage, vous installez vos gestionnaires de signaux Unix à l'aide de 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;
}Dans vos gestionnaires de signaux Unix, vous écrivez un octet sur le côté « écriture » d’une paire de sockets, puis vous quittez la fonction. Cela provoque l’émission du signal `activated()` par l’ QSocketNotifier correspondant, ce qui déclenche à son tour l’exécution de la fonction de slot Qt appropriée.
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));
}Dans les fonctions de slot connectées aux signaux () de l’ QSocketNotifier::activated, vous lisez l’octet. Vous êtes désormais de retour en toute sécurité dans Qt avec votre signal, et vous pouvez effectuer toutes les opérations Qt que vous n’étiez pas autorisé à effectuer dans le gestionnaire de signaux 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.