2012-01-18 12 views
5

Actualmente estoy usando un script para llamar al pkill para finalizar mi programa C++. Sin embargo, noté que los destructores no eran llamados desde mis rastros cuando usaba pkill.La mejor manera de salir de un programa correctamente sin usar pkill

¿Hay alguna otra buena manera de salir del programa con elegancia?
pkill parece un poco desordenado y algunos registros en el búfer no se graban. Me gustaría poder descargar mis archivos y cerrar todos los recursos programáticamente (en lugar de depender del O/S para limpiar mi desorden).

La aplicación funciona 24/7 sin ningún problema, el único momento en que quiero detenerlo es durante el mantenimiento. La aplicación no tiene ninguna interfaz de usuario para que escriba exit.

+0

¿Qué tipo de aplicación es? –

+0

@BasileStarynkevitch, es una aplicación de producción que recibe comandos de otro sistema para realizar algunos cálculos y monitoreos. Debería haber mencionado que cualquier cambio debe ser probado completamente antes de que entre en producción. –

+1

Entonces es muy probable que ya tenga algún evento de bucle ... Entonces agregar una tubería de control podría ser más simple ... Véase también mi respuesta ... –

Respuesta

4

Lo hace mediante la definición de un manejador de señales para SIGTERM lo largo de estas líneas:

En algún lugar de las necesidades de inclusión de bloque:

#include <signal.h> 
#include <stdio.h> 

Sí , estamos haciendo i C estilo!

En algún lugar de la parte de inicialización de su código:

signal (SIGTERM, handler); 

y luego definir el código de manejadores de señales (ras todo, etc):

void handler(int num) 
{ 
    // we might use this handler for many signals 
    switch (num) 
    { 
    case SIGTERM: 
     // clean up code. 
     break; 
    } 
} 

Ahora cuando se ejecuta pkill <app>, donde <app> es el nombre del ejecutable, se ejecutará el código para handler().

Sin conmutadores, se enviará la señal predeterminada SIGTERM a la aplicación. Si elige usar una señal diferente, deberá asegurarse de enviar la misma señal que "captura" en el handler().

La información relevante se puede encontrar en man 7 signal y, por supuesto, man kill.

+0

Sin embargo, mantendría la señal 'SIGTERM' predeterminada, que fue diseñada para una terminación elegante (y también es la señal que enviaría la secuencia de apagado del sistema). –

+0

Después de reflexionar, estoy de acuerdo, 'SIGTERM' tiene más sentido para esto. 'SIGHUP' probablemente se usa con más frecuencia para señalar una recarga o algo similar. – zrvan

+0

@BasileStarynkevitch He actualizado la respuesta. – zrvan

3

La mejor manera es manejar una señal en el programa, y ​​luego enviar esa señal usando kill. En el controlador de señal, marque un indicador que hará que el bucle principal finalice.

4

A menos que modifiques la aplicación de destino, no veo la manera.

considerar lo siguiente:

int main() 
{ 
    MyClass a; 
    while (true) 
    { 
    } 
} 

Habría que decirle al programa para salir del bucle. Pero a menos que tengas algún mecanismo de manejo de señales en tu aplicación, eso parece imposible.

Se necesitaría algo así como:

int main() 
{ 
    MyClass a; 
    while (!killSignalReceived()) 
    { 
    } 
} 
+1

¿Por qué 'while (true && ...)'? –

+0

@LieRyan :)) En mi cabeza, cierto podría haber sido cualquier cosa, ahora veo que es redundante. –

4

Además de Zrvan's answer, tenga en cuenta que solo un conjunto restringido de funciones se puede llamar con seguridad desde un manejador de señal. La página del manual signal(7) y los estándares de Posix requieren que solo funciones de señal segura asíncrona se puedan llamar directa o indirectamente dentro de un manejador de señal.Tenga en cuenta que printf o malloc no son seguros dentro de un manejador de señal. El código del manejador de señal es difícil de escribir (y no se puede depurar fácilmente, porque el envío de señal no es reproducible).

Como sugiere la documentación Glibc, su controlador de señal podría simplemente establecer una variable volatile sig_atomic_t, que su bucle principal [s] probaría y manejaría.

También podría decidir, si su aplicación está basada en eventos, que algún socket o pipe con nombre está dedicado a controlarlo. Ese bucle de evento (tal vez usando select(2) o poll(2), o incluso pselect o ppoll) podría manejar el mensaje de control en la tubería o zócalo.

Puede que le interesen las bibliotecas de bucles de eventos como libevent. También puede utilizar una biblioteca de servidor HTTP como onion o Wt. También podría estar interesado por SNMP o D-bus.

Un truco para superar la limitación de los manejadores de señal es hacer que escriban en una tubería para el mismo proceso, como p. Qt's doc está sugiriendo. Luego, el bucle de evento manejaría la lectura en esa tubería.

Si su aplicación es multiproceso, el manejo de la señal es más complicado. Algunas señales se entregan a un hilo individual.

+0

¡Esto es bueno, cosas buenas! – zrvan

Cuestiones relacionadas