2012-03-18 22 views
33

C++ 11 presenta una nueva forma de finalizar la ejecución del programa: std::quick_exit.¿Cuál es la diferencia entre std :: quick_exit y std :: abort y por qué se necesitó std :: quick_exit?

Citando al N3242 18,5 (p 461).:

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

Efectos: Funciones registradas por las llamadas a at_quick_exit se llaman en el orden inverso al de su inscripción, salvo que una función será llamada después de que cualquier función previamente registrada que tenía ya se haya llamado en el momento en que se registró. Los objetos no deben destruirse como resultado de llamar al 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á al terminate(). [Nota: at_quick_exit puede llamar a una función registrada de un hilo diferente que el que lo registró, por lo que las funciones registradas deben no depender de la identidad de los objetos con duración de almacenamiento de hilo. - nota final] Después de llamar a las funciones registradas, quick_exit deberá llamar al _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) sólo se diferencian en la capacidad de pasar a la situación del proceso principal, se plantea la pregunta.

¿Quiere decir que la única diferencia en la semántica entre std::quick_exit y std::abort son llamadas funciones que std::quick_exit registraron usando std::at_quick_exit y permite establecer el estado devuelto?

¿Cuál fue el motivo por el que se introdujo esta función?

Respuesta

34

Hay una buena escritura hasta available here, sólo voy a resumirlo. 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 hilos que salgan, típicamente señalando un evento, espera a que los hilos terminen y luego sale 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 tentador para este problema: llamar _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.

+5

Además, dado que 'abort 'señala' SIGABRT', típicamente se generará una llamada 'abortada' (aunque esto es configurable) en * * core dump ** on * nix, o en una ventana emergente en Windows (p. ej. _Program ha dejado de funcionar, Close/Debug_). Solo use 'abort' cuando termine debido a una ** condición inesperada ** y quiera un coredump/minidump ** diagnosticar el motivo ** de la condición inesperada. – vladr

2

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

std::abort normalmente aborta su aplicación, esto debe ser llamado cuando ocurre una situación anormal y su aplicación debe cerrarse sin realizar ninguna limpieza. Desde el std::abort documentación:

causa la terminación anormal del programa a menos SIGABRT está siendo capturado por un manejador de señales para indicar pasado y el manejador no vuelve.

Cuando desee realizar algunas limpiezas, std::quick_exit será más apropiado. Esta última función también le permite detener su aplicación correctamente, ya que termina llamando al std::_Exit en 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 le 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, hay 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.

+1

Y es que aún sin resolver - ¿por qué permitir hacer algunas limpiezas y no todos, cuando la terminación se hace "gracia"? Nunca he visto 'quick_exit' en un código real, pero si lo tengo en la revisión del código, probablemente estaría tentado de pedirle que lo complete o no haga nada. ¿Hay alguna fuente de WG21 sobre esto? –

+0

Si quiere una limpieza completa, entonces debería usar "exit". quick_exit es más rápido, ya que no llama a ningún desctructor automático de variables de subprocesos locales y estáticos. Creo que sería mejor comparar std :: quick_exit con std :: exit, ya que ambos permiten al usuario realizar un cierre gracefull, mientras que std :: abort básicamente termina su aplicación anormalmente. – mfontanini

+5

Los destructores de C++ suelen hacer cosas (como memoria libre) que no son necesarias cuando el proceso se está cerrando (porque el sistema operativo lo hará). Supongo que 'quick_exit' te permite limpiar un poco, pero deja el resto al SO. –

19

La razón de ser de std::quick_exit se discute en N1327 y N2440. Las diferencias clave entre quick_exit, _Exit, y exit preocupaciones el manejo de destructores estáticas y el lavado de información crítica para almacenamiento estable:

  • std::_Exit: no ejecuta destructores estáticas o flush IO crítico.
  • std::exit: ejecuta destructores estáticos y los colores IO crítico.
  • std::quick_exit: no se ejecuta destructores estáticas, pero lo hace a ras IO crítico.

(Como se ha mencionado, std::abort simplemente envía SIGABRT.)

+2

No veo ninguna evidencia en el estándar que std :: quick_exit limpie IO crítico. De hecho, el estándar dice "Nota: los búferes de archivos estándar no se vacían". ¿Cuál es la base de su creencia de que std :: quick_exit vacía el IO crítico y, para el caso, qué quiere decir con IO "crítico"? – KnowItAllWannabe

+2

@KnowItAllWannabe: Está definiendo crítico como "te preocupaste lo suficiente por registrar un manejador' at_quick_exit': –

Cuestiones relacionadas