2013-03-06 12 views
19

Wenn ich aus irgendeinem Grund eine fatale Situation in meinem Programm feststellen, und ich möchte mit einem Fehlercode beenden. Manchmal liegt der Kontext des schwerwiegenden Fehlers außerhalb des Bereichs anderer Dateideskriptoren. empfiehlt es sich, diese Dateideskriptoren zu schließen. Soweit ich weiß, werden diese Dateien automatisch geschlossen, wenn der Prozess abbricht.ist es eine gute Praxis, Dateideskriptoren beim Beenden zu schließen

+0

Gestalten Sie Ihr System so, dass es immer die Möglichkeit, eine saubere Abschaltung durchzuführen. Letzteres beinhaltet das Freigeben/Entsperren von Ressourcen, die noch von dem System verwendet werden, das gerade heruntergefahren wird. – alk

+0

Als Import sagt das richtig, explizit ist immer besser als implizit !! – Kaunteya

+0

@alk Dies ist ein kompliziertes Altsystem, Kaskadierungsfehler sind nicht möglich und Refactoring ist keine Option. – stdcall

Antwort

13

Dateien werden automatisch geschlossen, aber es ist eine gute Übung.

Siehe valgrind auf diesem Beispiel

[email protected]:~$ cat demo.c 
#include <stdio.h> 

int main(void) 
{ 
    FILE *f; 

    f = fopen("demo.c", "r"); 
    return 0; 
} 
[email protected]:~$ valgrind ./demo 
==3959== Memcheck, a memory error detector 
==3959== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al. 
==3959== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info 
==3959== Command: ./demo 
==3959== 
==3959== 
==3959== HEAP SUMMARY: 
==3959==  in use at exit: 568 bytes in 1 blocks 
==3959== total heap usage: 1 allocs, 0 frees, 568 bytes allocated 
==3959== 
==3959== LEAK SUMMARY: 
==3959== definitely lost: 0 bytes in 0 blocks 
==3959== indirectly lost: 0 bytes in 0 blocks 
==3959==  possibly lost: 0 bytes in 0 blocks 
==3959== still reachable: 568 bytes in 1 blocks 
==3959==   suppressed: 0 bytes in 0 blocks 
==3959== Rerun with --leak-check=full to see details of leaked memory 
==3959== 
==3959== For counts of detected and suppressed errors, rerun with: -v 
==3959== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4) 

Wie Sie sehen können, wirft es ein Speicher

Leck

Auf bestimmten Umständen können Sie nutzen atexit() machen:

#include <stdio.h> 
#include <stdlib.h> 

static FILE *f; 

static void free_all(void) 
{ 
    fclose(f); 
} 

static int check(void) 
{ 
    return 0; 
} 

int main(void) 
{ 
    atexit(free_all); 
    f = fopen("demo.c", "r"); 
    if (!check()) exit(EXIT_FAILURE); 
    /* more code */ 
    return 0; 
} 
+4

'FILE' Zeiger, der von' fopen() 'zurückgegeben wird, ist kein Dateideskriptor. Es ist ein Dateistream, dem ein Puffer zugeordnet ist. Wenn also Ihr Programm von 'main' zurückkehrt, ohne den Aufruf' fclose() 'auszuführen, bleibt dieser Speicher durch undicht, wie valgrind zeigt. Die Frage nach den Filedeskriptoren bleibt unbeantwortet. –

+2

@PavelZhuravlev ops, Sie haben Recht, Entschuldigung dafür –

5

Soweit ich weiß, werden diese Dateien automatisch geschlossen, wenn der Prozess abbricht.

Verlassen Sie sich nicht darauf. Konzeptionell, wenn der Prozess stirbt, ist es Ihre Verantwortung frei belegten Speicher, schließen nicht-standard-Dateideskriptoren, etc. Natürlich wird jedes gesunde Betriebssystem (und sogar Windows) nach Ihrem Prozess aufräumen, aber das ist nicht etwas zu erwarten von.

3

Ja. Angenommen, Ihr Hauptprogramm ist jetzt eine Klasse in einem separaten Programm. Jetzt haben Sie ein Ressourcenleck beschrieben. Sie verletzen im Wesentlichen die Kapselung, indem Sie sich auf den globalen Programmzustand verlassen, d. H. Den Status des Prozesses - nicht Ihr Modul, keine Klasse, keine ADT, kein Thread, sondern den gesamten Prozess -, der sich in einem Shutdown-Zustand befindet.

0

Es gibt keine Garantie in der C-Sprache, dass das Betriebssystem etwas gegen die Unordnung tun wird, die Sie zurückgelassen haben. Es liegt außerhalb des Anwendungsbereichs des Programmierstandards. Obwohl C implizit davon ausgeht, dass Sie alle Standard-Bereinigungsfunktionen (malloc fclose usw.) aufrufen, wie Sie es tun sollten.

Also hängt alles vom Betriebssystem ab. Da Ihre Frage kein bestimmtes Betriebssystem betrifft, kann sie nicht beantwortet werden. Zurzeit machen alle großen kommerziellen Desktop-Betriebssysteme eine Säuberung, aber das ist keine Entschuldigung dafür, schlampiges Programmieren zu üben.

Und dann, nehmen Sie an, Ihr Programm ist nicht gleich einem OS-Prozess/ausführbare Datei, aber es besteht aus einem Thread, einem Windows DLL, einem Treiber oder ähnlichem, im selben Speicherplatz wie der übergeordnete Prozess. Sie geben dann Ressourcen aus und stehlen Speicher vom übergeordneten System.

6

Die klassischen Leitfaden für POSIX-Programmierung „Erweiterte Programmierung in UNIX-Umgebung“ heißt es:

Wenn ein Prozess beendet wird, werden vom Kernel automatisch alle seiner geöffneten Dateien geschlossen. Viele Programme nutzen diese Tatsache und schließen geöffnete Dateien nicht explizit.

Sie haben das Betriebssystem in Ihrer Frage nicht erwähnt, aber ein solches Verhalten sollte von jedem Betriebssystem erwartet werden. Wenn Ihr Programmsteuerungsfluss exit() oder return von main() kreuzt, ist es die Systemverantwortung, nach dem Prozess zu bereinigen.

Es besteht immer die Gefahr von Fehlern bei der Betriebssystemimplementierung.Auf der anderen Seite muss das System viel mehr als mehrere offene Dateideskriptoren bei der Prozessbeendigung freigeben: Speicher belegt durch das Abbild der ausführbaren Datei, Stapel, Kernel-Objekte, die dem Prozess zugeordnet sind. Sie können dieses Verhalten nicht vom Benutzerbereich aus steuern, sondern nur darauf, dass es ordnungsgemäß funktioniert. Also, warum kann sich ein Programmierer nicht auf das automatische Schließen der fd s verlassen?

Also, das einzige Problem mit fd offen ist möglicherweise die Programmierstil Frage. Und, wie im Fall der Verwendung von stdio Objekten (d. H. Sachen, die um die vom System bereitgestellte Datei-E/A aufgebaut sind), können Sie (etwas) verwirrende Warnungen während des Valminding erhalten. Was die Gefahr von undichten Systemressourcen angeht, sollten Sie sich keine Sorgen machen, es sei denn, Ihre BS-Implementierung ist wirklich fehlerhaft.

0

C garantiert, dass alle geöffneten Dateien geschlossen werden, wenn Ihr Programm normal beendet wird (z. B. über 10 oder eine Rückgabe von main). Wenn Ihr Programm jedoch abnormal beendet wird, z. Es wird vom Betriebssystem geschlossen, da ein NULL-Zeiger verwendet wird. Das Schließen der Dateien obliegt dem Betriebssystem. Daher ist es eine gute Idee, sicherzustellen, dass Dateien geschlossen werden, wenn sie im Falle einer unerwarteten Beendigung nicht mehr benötigt werden.

Der andere Grund ist Ressourcengrenzen. Bei den meisten Betriebssystemen sind die Anzahl der geöffneten Dateien (und viele andere Dinge) begrenzt. Daher empfiehlt es sich, diese Ressourcen zurückzugeben, sobald sie nicht mehr benötigt werden. Wenn jedes Programm alle seine Dateien auf unbestimmte Zeit offen ließ, konnten Systeme ziemlich schnell Probleme bekommen.

0

Jedes vernünftige Betriebssystem (sicherlich jede Form von Linux oder Windows) schließt die Dateien, wenn das Programm beendet wird. Wenn Sie ein sehr einfaches Programm haben, müssen Sie die Dateien wahrscheinlich nicht bei Beendigung schließen. Allerdings schließt die Dateien explizit noch gute Praxis ist, aus den folgenden Gründen:

  1. , wenn Sie es mit dem O verlassen Sie keine Kontrolle über den Auftrag haben, in dem die Dateien geschlossen werden, was zu Konsistenzproblemen führen kann (wie in einer Datenbank mit mehreren Dateien).

  2. Wenn beim Schließen der Datei Fehler auftreten (z. B. E/A-Fehler, Fehler wegen zu wenig Speicherplatz usw.), haben Sie keine Möglichkeit, sie zu melden.

  3. Es kann zu Interaktionen mit Dateisperren kommen, die behandelt werden müssen.

  4. eine Routine, alle Dateien schließen Sie alle anderen clean-up verarbeiten kann, dass das Programm muss zur gleichen Zeit (Spülung Puffer, zum Beispiel)

Verwandte Themen