c++ c++11 language-lawyer

c++ - ¿Cuál es la diferencia entre std:: quick_exit y std:: abort y por qué se necesitó std:: quick_exit?



c++11 language-lawyer (3)

C ++ 11 presenta una nueva forma de finalizar la ejecución del programa std::quick_exit .

Citando el N3242 18.5 (página 461):

[[noreturn]] void quick_exit(int status) noexcept;

Efectos: las funciones registradas por las llamadas a at_quick_exit se llaman en el orden inverso al de su registro, excepto que se llamará a una función después de las funciones previamente registradas que ya se habían llamado en el momento en que se registró. Los objetos no se destruirán como resultado de llamar a quick_exit . Si el control deja una función registrada llamada por quick_exit porque la función no proporciona un controlador para una excepción lanzada, se llamará a terminate() . [Nota: at_quick_exit puede llamar a una función registrada desde un hilo diferente al que lo registró, por lo que las funciones registradas no deben basarse en la identidad de los objetos con duración de almacenamiento de hilo. - nota final] Después de llamar a las funciones registradas, quick_exit llamará a _Exit(status) . [Nota: los búferes de archivos estándar no se lavan. Ver: ISO C 7.20.4.4. - nota final]

Como la definición de std::abort(void) y std::_Exit(int status) difieren solo en la capacidad de pasar el estado al proceso principal, plantea mi pregunta.

¿Significa que la única diferencia en semántica entre std::quick_exit y std::abort es que std::quick_exit llama a funciones registradas usando std::at_quick_exit y permite establecer el estado devuelto?

¿Cuál fue la razón para introducir esta función?


Hay un buen artículo disponible aquí , lo resumiré. Esta característica se agregó para abordar específicamente la dificultad de finalizar un programa limpiamente cuando utiliza subprocesos. Por naturaleza, la salida se inicia por un evento altamente asincrónico, el usuario cierra la interfaz de usuario, el administrador apaga la máquina, etc. Esto sucede sin tener en cuenta el estado de los hilos que el programa inició, casi siempre están en un estado altamente impredecible.

En un mundo ideal, la función main () del programa pide a los subprocesos que salgan, generalmente al señalar un evento, espera a que los subprocesos finalicen y luego sale de main () para un apagado limpio a través de exit (). Sin embargo, ese ideal es muy difícil de lograr. Un hilo podría estar enterrado en el interior de una llamada al sistema, por ejemplo, esperando que se complete alguna E / S. O está bloqueando un objeto de sincronización que necesita ser señalado por otro hilo en el orden correcto. El resultado rara vez es agradable, los programas reales a menudo se estancan al salir. O se cuelga cuando el orden de apagado es inesperado.

Hay una solución simple y muy tentadora para este problema: llamar a _exit () en su lugar. Kaboom, el programa terminó, el sistema operativo arrastra la metralla. Pero claramente sin ningún tipo de limpieza, muy complicado a veces con artefactos como un archivo medio escrito o una transacción de base de datos incompleta.

std :: quick_exit () ofrece la alternativa. Similar a _exit () pero con la opción de ejecutar código, lo que se registró con at_quick_exit.


La justificación para std::quick_exit se trata en N1327 y N2440 . Las principales diferencias entre quick_exit , _Exit y exit refieren al manejo de destructores estáticos y a la descarga de información crítica al almacenamiento estable:

  • std::_Exit : no ejecuta destructores estáticos o elimina IO crítico.
  • std::exit : ejecuta destructores estáticos y vacía el IO crítico.
  • std::quick_exit : no ejecuta destructores estáticos, pero sí vacía el IO crítico.

(Como se mencionó, std::abort solo envía SIGABRT ).


std::abort terminará su aplicación sin llamar a ninguna función registrada usando "at_exit / at_quick_exit". Por otro lado, std::quick_exit llamará, como ha señalado, a las funciones registradas usando std::at_quick_exit .

std::abort típicamente anula su aplicación, esto debe invocarse cuando ocurre una situación anormal y su aplicación debe cerrarse sin realizar ninguna limpieza. De la documentación de std::abort :

Causa la terminación anormal del programa a menos que SIGABRT sea atrapado por un manejador de señal que se pasa a la señal y el manejador no regresa.

Cuando desee realizar algunas limpiezas, std::quick_exit será más adecuado. Esta última función también le permite detener su aplicación correctamente, ya que termina llamando a std::_Exit lugar de señalizar una señal como std::abort (que señala a SIGABRT, haciendo que la aplicación se detenga anormalmente).

std::exit permite salir de su aplicación correctamente, mientras sigue limpiando automáticamente, enhebrar variables locales y estáticas. std::quick_exit no. Es por eso que hay un nombre "quick_" en su nombre, es más rápido porque omite la fase de limpieza.

Por lo tanto, existe una diferencia semántica real entre ambas funciones. Uno detiene la aplicación de forma anormal y el otro realiza una salida graciosa, lo que le permite realizar algunas limpiezas.