c++ - mundo - funcion exit en c
Eliminación garantizada de archivos al finalizar el programa(C/C++) (8)
Win32''s FILE_FLAG_DELETE_ON_CLOSE
tiene FILE_FLAG_DELETE_ON_CLOSE
, pero estoy en Linux.
Quiero abrir un archivo temporal que siempre se eliminará al finalizar el programa. Puedo entender que en el caso de un bloqueo del programa no sea práctico garantizar esto, pero en cualquier otro caso me gustaría que funcione.
Sé sobre RAII. Sé sobre señales. Sé sobre atexit(3)
. Sé que puedo abrir el archivo y eliminarlo inmediatamente, y el archivo seguirá siendo accesible hasta que se cierre el descriptor del archivo (que incluso maneja un bloqueo). Ninguno de estos parece una solución completa y directa:
- RAII: estado allí, hecho eso: tengo un objeto cuyo destructor elimina el archivo, pero no se llama al destructor si el programa termina con una señal.
- señales: estoy escribiendo una biblioteca de bajo nivel que hace que el registro de un manejador de señal sea una proposición difícil. Por ejemplo, ¿qué pasa si la aplicación usa señales en sí? No quiero pisar los dedos de los pies. Podría considerar algún uso inteligente de
sigaction(2)
para hacer frente ... pero aún no he pensado lo suficiente en esta posibilidad. -
atexit(3)
: aparentemente inútil, ya que no se llama durante la terminación anormal (por ejemplo, a través de una señal). -
unlink(2)
preventivaunlink(2)
: esto es bastante bueno, excepto que necesito que el archivo permanezca visible en el sistema de archivos (de lo contrario, el sistema es más difícil de supervisar / solucionar problemas).
¿Qué harías aquí?
Explicación adicional
Supliqué un detalle en mi publicación original, que ahora me doy cuenta de que debería haber incluido. El "archivo" en este caso no es estrictamente un archivo normal, sino una cola de mensajes POSIX. Lo creo a través de mq_open()
. Se puede cerrar a través de mq_close()
o close()
(el primero es un alias para este último en mi sistema). Se puede eliminar del sistema a través de mq_unlink()
. Todo esto lo hace análogo a un archivo normal, excepto que no puedo elegir el directorio en el que reside el archivo. Esto hace que la respuesta más popular actual (colocar el archivo en /tmp
) sea inviable, porque el "archivo" es creado por el sistema en un sistema de archivos virtual con capacidad muy limitada. (He montado el sistema de archivos virtual en /dev/mqueue
, siguiendo el ejemplo en man mq_overview
).
Esto también explica por qué necesito que el nombre permanezca visible (lo que hace que el enfoque de desvinculación inmediata sea inviable): el "archivo" debe compartirse entre dos o más procesos.
El requisito de que el nombre permanezca visible mientras se ejecuta el proceso hace que esto sea difícil de lograr. ¿Puedes volver a visitar ese requisito?
Si no, entonces probablemente no haya una solución perfecta. Consideraría combinar una estrategia de manejo de señal con lo que sugiere Kamil Kisiel. Puede realizar un seguimiento de los manejadores de señal instalados antes de instalar sus manejadores de señal. Si el controlador predeterminado es SIG_IGN, normalmente no instalaría su propio controlador; si es SIG_DFL, lo recordarías; si se trata de otra cosa, un manejador de señal definido por el usuario, recordarías ese puntero e instalarías el tuyo. Cuando se llamaba a su controlador, hacía lo que fuera necesario y luego llamaba al controlador recordado, encadenando así a los controladores. También instalaría un controlador atexit (). También documentará que hace esto y las señales para las que lo hace.
Tenga en cuenta que el manejo de la señal es una estrategia imperfecta; SIGKILL no se puede capturar, y no se llamará al controlador atexit (), y el archivo se dejará alrededor.
La sugerencia de David Segond, un daemon de nombre de archivo temporal, es interesante. Para procesos simples, es suficiente; si el proceso que solicita el archivo temporal se bifurca y espera que el hijo posea el archivo a continuación (y salga), entonces el daemon tiene problemas para detectar cuándo muere el último proceso que lo usa, porque no conoce automáticamente los procesos que lo tienen abierto.
En el pasado, he creado un "administrador de archivos temporales" que realiza un seguimiento de los archivos temporales.
Uno solicitaría un nombre de archivo temporal al administrador y este nombre fue registrado.
Una vez que ya no necesita el nombre del archivo temporal, informe al administrador y el nombre del archivo no está registrado.
Al recibir una señal de terminación, se destruyeron todos los archivos temporales registrados.
Los nombres de archivo temporales estaban basados en UUID para evitar colisiones.
Puede hacer que el proceso se bifurque después de crear el archivo, y luego esperar que el hijo se cierre, y luego el padre puede desvincular el archivo y salir.
Si solo está creando un archivo temporal, simplemente créelo en /tmp
o en un subdirectorio del mismo. Luego haga un mejor esfuerzo para eliminarlo cuando lo haga a través de atexit(3)
o similar. Siempre que use nombres únicos recogidos a través de mkstemp(3)
o similar, incluso si no puede eliminarse debido a un bloqueo del programa, no correrá el riesgo de leerlo nuevamente en ejecuciones posteriores u otras condiciones similares.
En ese punto, es solo un problema a nivel de sistema para mantener /tmp
clean. La mayoría de las distribuciones lo limpian al arrancar o al apagar, o ejecutan un cronjob regular para eliminar archivos viejos.
Tal vez alguien sugirió esto, pero no puedo detectarlo, teniendo en cuenta todos sus requisitos, lo mejor que puedo pensar es tener el nombre de archivo de alguna manera comunicado a un proceso principal, como un script de inicio, que se limpiará después el proceso muere, si no lo hubiera hecho. Esto es quizás más conocido como un perro guardián, pero luego con el caso de uso más común agregado para matar y / o reiniciar el proceso cuando de alguna manera falla.
Si el proceso principal también muere, no tiene suerte, pero la mayoría de los entornos de script son bastante sólidos y rara vez mueren a menos que se rompa el script, que a menudo es más fácil de mantener que un programa.
Me acabo de unir a y te encontré aquí :)
Si su problema es administrar archivos mq y evitar que se acumulen, no es necesario que garantice la eliminación del archivo al finalizar. Si solo desea que los archivos inútiles se acumulen, entonces puede ser todo lo que necesita mantener un diario. Agregue una entrada al archivo de diario después de abrir un mq, otra entrada cuando se cierre y cuando se inicialice su biblioteca, verifique la incoherencia en el diario y tome las medidas necesarias para corregir la incoherencia. Si le preocupa que se bloquee cuando se mq_open/mq_close
, también puede agregar una entrada de diario justo antes de que se llamen esas funciones.
- Tenga un directorio de mantenimiento de libros para archivos temporales debajo de su directorio de puntos.
- Al crear un archivo temporal, primero cree un archivo de mantenimiento en el directorio de mantenimiento de libros que contiene la ruta o el UUID en su archivo temporal.
- Crea ese archivo temporal.
- Cuando se elimina el archivo temporal, entonces elimine el archivo de la contabilidad.
- Cuando se inicia el programa, escanee el directorio de mantenimiento de libros en busca de archivos que contengan rutas a archivos temporales e intente eliminarlos si los encuentra, elimine los archivos de mantenimiento de libros.
- (Inicie sesión ruidosamente si falla un paso).
No veo formas de hacerlo de manera más simple. Este es el estándar que cualquier programa de calidad de producción debe pasar; +500 líneas fácilmente.
¿ Realmente necesitas el nombre para permanecer visible?
Supongamos que tiene la opción de desvincular inmediatamente el archivo. Entonces:
desvinculación preventiva (2): esto es bastante bueno, excepto que necesito que el archivo permanezca visible en el sistema de archivos (de lo contrario, el sistema es más difícil de supervisar / solucionar problemas).
Todavía puede depurar en un archivo eliminado, ya que aún será visible en
/proc/$pid/fd/
. Siempre que conozca los pides de sus procesos, enumerar sus archivos abiertos debería ser fácil.los nombres deben permanecer visibles durante el funcionamiento normal porque se comparten entre programas.
Todavía puede compartir el archivo abierto eliminado entre procesos al pasar el descriptor de archivo sobre los sockets de dominio de Unix. Vea la forma Portable para pasar el descriptor de archivo entre diferentes procesos para más información.