2012-10-08 56 views

Respuesta

11

El la primera llamada debe devolver 0; la segunda llamada debe devolver -1, y establecer errno en EBADF.

Debe evitar que ocurra la segunda llamada configurando fd en un número incorrecto conocido, p. Ej. un -1 inmediatamente después de la primera llamada de close, y posteriormente comprobar fd antes de hacer la segunda llamada (y no hacer la llamada si fd es -1):

close(fd); 
fd = -1; 
... 
// More code 
... 
if (fd != -1) { 
    close(fd) 
    fd = -1; 
} 

Este patrón de código ayudará cuando necesite hacer llamadas a close desde varios lugares, pero no está seguro de si el archivo está abierto o si ya se ha cerrado. Pasar -1 a close es inofensivo (obtendría un EBADF, por supuesto).

+0

¿Por qué deberías evitar que ocurra la segunda llamada? –

+0

Establecer fd a -1 no tiene ningún efecto (ciertamente no "evita que la segunda llamada suceda") ... tanto eso como un fd cerrado rendimiento EBADF. –

+5

@JimBalter establecer fd en -1 evitaría el riesgo de cerrar muy ocasionalmente un archivo que acababa de abrir otro subproceso. – simonc

7

Debe ser inofensivo, a menos que estés roscado o hacer algo entre las dos llamadas a cerrar. Entonces podría terminar cerrando un fd que algo más en su programa ha abierto.

La forma en que el enhebrado es relevante es que las bibliotecas casi siempre hacen cosas raras a sus espaldas. Libc abrirá archivos para buscar mensajes de error u otras cosas dependientes de la configuración regional, la resolución puede abrir archivos de configuración, etc. Si cierra un descriptor de archivo y lo cierra de nuevo, en un entorno enhebrado puede terminar fácilmente en una situación donde el archivo el descriptor ha sido reutilizado por una biblioteca y lo cierra detrás de su parte posterior.

+0

+1 por mencionar posibles problemas en un entorno con hebras. – alk

+0

La * primera * llamada para cerrar podría cerrar un fd de otro hilo. Dos cierres no son relevantes para ese problema. La única forma de enhebrar relevante aquí es que el segundo podría no fallar si ese fd se volviera a abrir, pero eso no es interesante ... si no sincronizas tus hilos, pueden ocurrir todo tipo de cosas malas. –

+2

El valor devuelto por 'open()' es reciclado por el sistema operativo. Entonces, si el hilo A llama 'open()' y obtiene fd = 3, entonces 'close()' s it. Entonces, justo antes de que el hilo A llame 'close()' la segunda vez, el hilo B llamó 'open()' con éxito y obtuvo fd = 3 nuevamente. Entonces, ¿qué haría el segundo 'close()' llamado por el hilo A? – alk

1

Si el fd valor PF sigue siendo la misma la segunda llamada devolverá un error que el fd no es válida (EBADF - como dasblinkenlight señaló)

pensar en hacer somthing likg

if fd != -1) 
{ 
    close (fd); 
    fd = -1; 
} 
+1

Este tipo de cosas no tiene sentido, ya que cerrar (fd) no es indefinido o peligroso de alguna forma cuando fd ya está cerrado ... close (fd) y close (-1) hacen exactamente lo mismo. La única razón para establecer fd en -1 es asegurarse de que no sea un descriptor de archivo abierto válido, como 0. –

+0

Ok, las personas han notado que un descriptor de archivo puede haber sido reabierto en otro hilo, por lo que establecer fd = -1 es una buena práctica. Pero la prueba 'fd! = -1' no es estrictamente necesaria ... el efecto es el mismo sin ella. –

+1

Estoy de acuerdo con usted en que la prueba de -1 no es necesaria. Aún más: en una construcción de depuración lo omitiría, y registraría el error 'close()' volvería a continuación, para apuntarme al lío que creé que llevaría a intentar cerrar el archivo dos veces ... ;-) @ JimBalter – alk

3

La segunda llamada fallará con Errno: EBADF cuando porque para entonces, fd no es un descriptor de archivo activo.

No debería tener ningún efecto en la ejecución. Sin embargo, si se configuró un número de error antes del primer cierre, se perderá, por lo que no debe cerrar el descriptor de archivo dos veces.

+0

¡Ah, esta respuesta realmente dice algo válido! +1 –

4

El cierre de la misma FD debe ser el doble no mortal como otros han señalado, pero ten cuidado de código como este

close(fd); 
/* ... */ 
newfd = open(....); 
/* ... */ 
close(fd); 

Por el segundo cierre, no se puede estar seguro de si es en realidad fd lo mismo que newfd! Esto provocaría bloqueos siempre que intentara usar newfd.

Entonces (si hay código entre ambas llamadas close) no es seguro hacer esto. Siempre close descriptores de archivos exactamente una vez.Siempre free buffers exactamente una vez.

Cuestiones relacionadas