2010-09-10 12 views
6

Heredé recientemente un código que alguien más había escrito.¿Cuáles son las implicaciones de no cerrar un identificador de directorio en Perl?

descubrí que todo el código que un directorio se abrió a la lectura, nunca fue cerrado debido a que el desarrollador original tenía un problema de sintaxis - que estaba usando la función close para intentar cerrar un directorio manejar lugar de la función closedir .

El código fue algo como esto:

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

(que es otro buen punto de que se hace en Perl Best Practices (páginas 208,278) sobre la comprobación del retorno de la función close Si el regreso de close fuera. comprobado en este caso, estaría fallando con "Número de archivo incorrecto")

Desde entonces he cambiado esto a closedir, pero me hizo comenzar a preguntarme: Dado que el identificador de directorio nunca se cerró, ¿cuáles son las implicaciones negativas mantener un identificador de directorio abierto por una larga duración?

Este programa es más grande (3.500 líneas de código), se ejecuta durante un tiempo (5-10 minutos) y varias instancias de este programa se ejecutan al mismo tiempo. En el caso de este directorio en el ejemplo anterior, $dir es el mismo valor para todas las instancias. Si se ejecutaban 10 instancias de este programa al mismo tiempo, todas tenían un identificador de directorio abierto contra el mismo directorio durante 5 minutos o más. Estoy seguro de que Perl está cerrando automáticamente el identificador de directorio cuando finalice el programa, pero la mejor práctica dice que se cierre lo antes posible.

Me resulta más obvio que dejar los identificadores de archivo abiertos puede causar problemas (especialmente para los identificadores de archivo que están abiertos para escribir), pero ¿qué cosas malas pueden suceder al no cerrar un identificador de directorio?

La razón por la que estoy preguntando es porque ha habido una extraña circunstancia en la que este programa intentaba crear un archivo (en el directorio definido por $ dir anterior). El nombre de archivo tenía el PID incrustado en él, por lo que existe una menor probabilidad de que el archivo ya pudiera estar allí, pero Perl no pudo abrir el archivo para escribir, porque dijo que ya existía. Cuando miramos en el directorio, ese archivo no existía. Me pregunto si todos los manejadores de directorios abiertos en este directorio podrían causar tal problema.

No estoy seguro de si el sistema operativo hace la diferencia, pero este programa se ejecuta en AIX.

¡Gracias de antemano y feliz viernes!

Respuesta

11

Has perdido un descriptor de directorio, que probablemente cuenta como un descriptor de archivo. En última instancia, le haría daño si su programa abre suficientes directorios para quedarse sin descriptores de archivos. De lo contrario, es bastante inofensivo, aunque menos que ideal. Hace que el sistema (y Perl) guarden recursos alrededor de los cuales de otro modo podrían ser liberados.

Si el identificador de directorio era una variable local, no un nombre simple de estilo DIR, es posible que Perl limpie detrás de usted. Ver opendir que dice:

Abre un directorio llamado EXPR para su procesamiento por readdir, telldir, seekdir, rewinddir y closedir. Devuelve true si es exitoso. DIRHANDLE puede ser una expresión cuyo valor se puede utilizar como dirhandle indirecto, generalmente el nombre de dirhandle real. Si DIRHANDLE es una variable escalar indefinida (o matriz o elemento hash), a la variable se le asigna una referencia a un nuevo dirhandle anónimo. DIRANDES tienen su propio espacio de nombres separado de ARCHIVOS DE ARCHIVO.

+1

Incluso hoy en día algunos sistemas operativos son bastante tacaños con los descriptores de archivos (estoy viendo * usted *, Solaris, y su configuración predeterminada de 64-256). – mob

+8

@mobrule - Lo siento, no puedo publicar su comentario, debido a que no hay descriptores de archivos disponibles - Atentamente, StackOverflow Solaris Backend .... – DVK

7

No habrá consecuencias drásticas. Habrá un aumento muy leve en el uso de la memoria, desde el kernel mismo, que no puede liberar el iterador que usa internamente para recorrer la lista de entradas de directorio, y probablemente también desde el lado perl.

Aditcionalmente, mientras que cualquier descriptor en un directorio todavía esté abierto, los datos no pueden ser realmente eliminados del sistema de archivos. Si algún otro proceso externo borrara el directorio para el que tiene el control, dejaría de aparecer en las listas futuras del directorio, pero los datos aún tendrían que mantenerse en el disco y aún serían accesibles mediante el proceso con el manejador abierto. Eso podría dar lugar a números impares en el uso del disco, por ejemplo.

También tenga en cuenta que no necesariamente tiene que cerrar todos sus identificadores manualmente. Al utilizar controladores de archivo léxicas, el cierre se realiza automáticamente tan pronto como la última referencia al mango desaparece:

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

Ésta es una lección para utilizar siempre Archivo- léxica (y DIRECTORIO) maneja - manijas léxicas se cierran automáticamente cuando salen del alcance.

Así que solo estaría desperdiciando descriptores (como describe Jonathan) si 1. usó el controlador de estilo anterior, o 2. todo el código está en un script plano sin subrutinas u otro ámbito. Utilice buenas prácticas de programación y los errores inadvertidos serán menos :)

+0

Este opendir estaba en main, por lo que tenía un alcance global ... Usted Sin embargo, son absolutamente correctos: ¡las buenas prácticas de programación definitivamente reducirán los errores inadvertidos! – BrianH

+1

De acuerdo con su código, de todos modos usó un manejador de espada desnuda. Esos siempre tienen un alcance global a menos que los localice explícitamente. – rafl

Cuestiones relacionadas