Kann ich free () oder close () in einem Signalhandler ausführen? [Duplikat]

Dec 10 2020

Ich habe einen Code, der so aussieht:

//global variables

void signal_handler() {
    //deallocation of global variables
    free(foo);
    close(foo_2);
    exit(0);
}

int main () {
    signal(SIGINT, signal_handler);

    //irrelevant code
}

Wie Sie sehen, habe ich die CTRL+CUnterbrechung geändert , um die signal_handlerFunktion einmal auszuführen, anstatt den Prozess sofort abzubrechen. Ich habe irgendwo gelesen, dass einige Funktionen wie freeasync-sicher sind und NICHT in der ausgeführt werden, signal_handleraber ich bin mir nicht sicher.

Kann ich Funktionen wie ausführen free, close, exitoder sogar pthread_joinin einem Signalhandler?

Antworten

1 dratenik Dec 10 2020 at 15:46

Nein. Nur die in Man 7 Signalsicherheit aufgeführten Funktionen können sicher in einem Signalhandler aufgerufen werden.

closeist aufgeführt und sollte sicher sein. freeist nicht. Aus Gründen, warum Sie sich den Quellcode ansehen müssten (er enthält Sperren). exitist nicht sicher, da beliebige Bereinigungshandler aufgerufen werden können. Sie haben _exitdie abrupt ohne die Bereinigung beendet.

1 MarcoBonelli Dec 10 2020 at 15:46

Sie können technisch ein Programm kompilieren, das solche Funktionen in einem Signalhandler aufruft. Nichts hindert Sie daran. Es führt jedoch zu undefiniertem Verhalten, wenn die Funktion, die Sie ausführen möchten, nicht asynchron-signal-sicher ist. Es ist nicht so, als würde eine unsichere Funktion einfach "NICHT ausgeführt", wie Sie sagen, sie könnte es sehr gut, aber das wäre immer noch undefiniertes Verhalten.

Eine Liste der async-signal-sicheren Funktionen ist in dokumentiert man 7 signal-safety. Die close()Funktion ist sicher free()und phtread_join()nicht. Die exit()Funktion kann auch nicht sicher von einem Signalhandler aufgerufen werden. Wenn Sie einen solchen Kontext verlassen möchten, müssen Sie dies _exit()stattdessen verwenden.

Die einzige Möglichkeit, eine Funktion, die beim Empfang eines Signals nicht asynchrones Signal sicher ist, sicher aufzurufen, besteht darin, sich daran zu erinnern, dass Sie sie aufrufen müssen (z. B. eine globale Variable festlegen) und dies dann tun müssen, nachdem Sie vom Signalhandler zurückgekehrt sind.

1 JohnBode Dec 10 2020 at 16:30

Kurze Antwort ist nein:

7.1.4 Verwendung von Bibliotheksfunktionen
...
4 Es wird nicht garantiert, dass die Funktionen in der Standardbibliothek wiedereintrittsfähig sind, und sie können Objekte mit statischer oder Thread-Speicherdauer ändern. 188)
188) Daher kann ein Signalhandler im Allgemeinen keine Standardbibliotheksfunktionen aufrufen
C 2011 Online-Entwurf

Beispiel aus der Praxis für die Konsequenzen - Ich habe an einem System gearbeitet, das mit einer Access-Datenbank kommuniziert. Es gab einen Signalhandler, der versuchte, eine Fehlermeldung an die Konsole zu schreiben fprintf, der jedoch während des Signalverarbeitungsprozesses irgendwie stderrder MDB-Datei zugeordnet wurde, in der die Datenbank gespeichert war, die den Header überschrieb und die Datenbank irreparabel ruinierte.

Es gibt ehrlich gesagt nicht viel, was Sie in einem Signalhandler tun können , außer ein Flag zu setzen, das an anderer Stelle überprüft werden soll.

BasileStarynkevitch Dec 10 2020 at 16:24

Kann ich free () oder close () in einem Signalhandler ausführen?

Das solltest du definitiv nicht. Siehe Signal (7) und Signalsicherheit (7)

In der Praxis könnte es so funktionieren, als ob Sie vielleicht mehr als die Hälfte der Zeit möchten. IIRC, der GCC- Compiler macht das, was Sie wollen, und es funktioniert normalerweise.

Ein besserer Ansatz besteht darin, etwas Schreiben (2) in eine Pipe (7) (aus Ihrem Signalhandler heraus) zu verwenden und diese Pipe (in Ihrem Hauptprogramm) von Zeit zu Zeit mit Poll (2) oder ähnlichen Dingen zu überprüfen .

Oder Sie können einige volatile sigatomic_t flag;(möglicherweise sollte es auch sein _Atomic) in Ihrem Signalhandler setzen und dieses Flag an anderer Stelle (im Hauptprogramm außerhalb der Signalhandler) überprüfen.

Qt erklärt das besser als ich es in ein paar Minuten tun könnte.

Siehe unter Linux auch signalfd (2) und eventfd (2) .