Kann ich free () oder close () in einem Signalhandler ausführen? [Duplikat]
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+C
Unterbrechung geändert , um die signal_handler
Funktion einmal auszuführen, anstatt den Prozess sofort abzubrechen. Ich habe irgendwo gelesen, dass einige Funktionen wie free
async-sicher sind und NICHT in der ausgeführt werden, signal_handler
aber ich bin mir nicht sicher.
Kann ich Funktionen wie ausführen free
, close
, exit
oder sogar pthread_join
in einem Signalhandler?
Antworten
Nein. Nur die in Man 7 Signalsicherheit aufgeführten Funktionen können sicher in einem Signalhandler aufgerufen werden.
close
ist aufgeführt und sollte sicher sein. free
ist nicht. Aus Gründen, warum Sie sich den Quellcode ansehen müssten (er enthält Sperren). exit
ist nicht sicher, da beliebige Bereinigungshandler aufgerufen werden können. Sie haben _exit
die abrupt ohne die Bereinigung beendet.
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.
Kurze Antwort ist nein:
7.1.4 Verwendung von BibliotheksfunktionenC 2011 Online-Entwurf
...
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
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 stderr
der 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.
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) .