2010-09-10 10 views
6

Niedawno odziedziczyłem kod, który napisał ktoś inny.Jakie są konsekwencje nie zamykania uchwyt katalogu w Perlu?

odkryłem, że wszędzie w kodzie, że katalog został otwarty do czytania, to nigdy nie został zamknięty, ponieważ oryginalny deweloper miał problem składni - był przy użyciu funkcji close próbować zamknąć katalog obsłużyć zamiast funkcji closedir .

Kod było coś takiego:

opendir(DIR, $dir) or die "Cannot open $dir: $!\n"; 
@files = readdir(DIR); 
close(DIR); 

(co jest kolejnym dobrym punktem, który jest wykonany w Perl Best Practices (strony 208,278) o sprawdzenie powrotu funkcji close Jeśli powrót close były. sprawdzone w tym przypadku, byłby to błąd z "Bad file number".)

Od tego czasu zmieniłem to na closedir, ale zacząłem się zastanawiać: Ponieważ uchwyt katalogu nigdy nie był zamknięty, jakie są negatywne konsekwencje utrzymywać otwarty uchwyt katalogu na długi czas?

Ten program jest większy (3500 linii kodu), działa przez pewien czas (5-10 minut), a wiele wystąpień tego programu działa w tym samym czasie. W przypadku tego katalogu w powyższym przykładzie $dir ma taką samą wartość dla wszystkich wystąpień. Jeśli 10 wystąpień tego programu było uruchomionych w tym samym czasie, wszystkie miały otwarty uchwyt katalogu do tego samego katalogu przez 5 minut lub dłużej. Jestem pewien, że Perl automatycznie zamyka uchwyt katalogu po zakończeniu programu, ale najlepsza praktyka mówi, aby zamknąć to tak szybko, jak to możliwe.

Jest dla mnie bardziej oczywiste, że pozostawienie otwartych uchwytów plików może powodować problemy (zwłaszcza w przypadku otwartych do pisania uchwytów plików), ale co może się stać złego, nie zamykając uchwytu katalogu?

Powodem, dla którego pytam, jest fakt, że w czasie, gdy program próbował utworzyć plik (w katalogu zdefiniowanym przez $ dir powyżej) wystąpiła dziwna okoliczność. Nazwa pliku zawierała PID, więc jest mniejsza szansa, że ​​plik już istnieje, ale Perl nie mógł otworzyć pliku do zapisu, ponieważ powiedział, że już istniał. Kiedy zajrzeliśmy do katalogu, ten plik nie istniał. Zastanawiam się, czy wszystkie otwarte katalogi obsługuje ten katalog może spowodować taki problem?

Nie jestem pewien, czy system operacyjny robi różnicę, ale ten program działa w systemie AIX.

Z góry dziękuję i szczęśliwy piątek!

Odpowiedz

11

Zmarnowałeś deskryptor katalogu - który prawdopodobnie liczy się jako deskryptor pliku. Ostatecznie zaszkodziłoby to, gdyby twój program otworzył wystarczającą liczbę katalogów, aby zabrakło deskryptorów plików. W przeciwnym razie jest całkiem nieszkodliwy, ale nie idealny. To sprawia, że ​​system (i Perl) zachowuje zasoby, które w innym przypadku byłyby w stanie uwolnić.

Jeśli uchwyt katalogu był zmienną lokalną, a nie zwykłą nazwą stylu DIR, możesz mieć za sobą czyszczenie Perla. Zobacz: opendir, która mówi:

Powoduje otwarcie katalogu o nazwie WYRAŻ do przetworzenia przez readdir, telldir, seekdir, rewinddir i closedir. Zwraca true, jeśli zakończy się powodzeniem. DIRHANDLE może być wyrażeniem, którego wartość może być używana jako pośrednia dirhandle, zwykle prawdziwa nazwa dirhandle. Jeśli DIRHANDLE jest niezdefiniowaną zmienną skalarną (lub tablicą lub elementem hash), zmiennej przypisuje się odniesienie do nowego anonimowego dirhandle. DIRHANDLEs mają swoją własną przestrzeń nazw oddzieloną od FILEHANDLEs.

+1

Nawet dziś niektóre systemy operacyjne są dość skąpe z deskryptorami plików (patrzę na * ciebie *, solaris i domyślne ustawienie 64-256). – mob

+8

@mobrule - Przykro mi, nie mogę opublikować Twojego komentarza, ponieważ nie ma dostępnych deskryptorów plików - Z poważaniem, StackOverflow Solaris Backend .... – DVK

7

Nie będzie żadnych drastycznych konsekwencji. Nastąpi nieznaczne zwiększenie wykorzystania pamięci, z samego jądra, które nie może zwolnić iteratora, którego wewnętrznie używa do zapętlenia się przez listę pozycji katalogu, i prawdopodobnie także ze strony perl.

Adnotacyjnie, dopóki dowolny deskryptor do katalogu nadal jest otwarty, dane nie mogą być faktycznie usunięte z systemu plików. Jeśli jakiś inny proces zewnętrzny usunie katalog, do którego masz dostęp, przestanie on pojawiać się w przyszłych listingach katalogów, ale dane nadal będą przechowywane na dysku i nadal będą dostępne dla procesu z otwartym uchwytem. Może to spowodować na przykład nieparzyste liczby w użyciu dysku.

Pamiętaj też, że nie musisz ręcznie zamykać wszystkich uchwytów. Podczas korzystania z uchwytów plików leksykalne, zamykanie odbywa się automatycznie, gdy tylko ostatni odniesienie do uchwytu odchodzi:

{ # new scope 
    opendir(my $handle, ...) or ...; 
    ... 
} # implicit closedir happens here 
6

Jest to lekcja, aby zawsze używać Plik- leksykalnego (i directory-) uchwyty - uchwyty leksykalne są automatycznie zamknięte kiedy wykraczają poza zakres.

Więc marnujesz deskryptory (tak jak opisuje Jonathan), jeśli 1. użyłeś staromodnego globalnego uchwytu, lub 2. cały kod jest w płaskim skrypcie bez podprogramów lub innych zakresów. Korzystaj z dobrych praktyk programowania, a nieumyślne błędy będą mniejsze :)

+0

Ten opendir był w głównej wersji, więc miał zasięg globalny ... są jednak absolutnie poprawne - dobre praktyki programistyczne zdecydowanie zmniejszą nieumyślne błędy! – BrianH

+1

Zgodnie z twoim kodem, mimo wszystko użyłeś go. Te są zawsze globalnie określone, chyba że je jawnie zlokalizujesz. – rafl

Powiązane problemy