una - prototipos de funciones c++
Proporcionar/pasar argumento al manejador de señal (6)
¿Puedo proporcionar / pasar cualquier argumento al manejador de señal?
/* Signal handling */
struct sigaction act;
act.sa_handler = signal_handler;
/* some more settings */
Ahora, el controlador se ve así:
void signal_handler(int signo) {
/* some code */
}
Si quiero hacer algo especial, es decir, borrar archivos temporales, ¿puedo proporcionar esos archivos como argumento para este manejador?
Editar 0: Gracias por las respuestas. Generalmente evitamos / desalentamos el uso de variables globales. Y en este caso, si tiene un programa enorme, las cosas pueden salir mal en diferentes lugares y es posible que tenga que hacer mucha limpieza. ¿Por qué la API fue diseñada de esta manera?
Absolutamente. Puede pasar enteros y punteros a los manejadores de señal mediante el uso de sigqueue () en lugar del habitual kill ().
Almacene los nombres de los archivos en una variable global y acceda a ellos desde el controlador. La devolución de llamada del manejador de señal solo recibirá un argumento: la ID de la señal real que causó el problema (por ejemplo, SIGINT, SIGTSTP)
Editar 0: "Debe haber una razón sólida para no permitirle argumentos al controlador". <- Hay un vector de interrupción (básicamente, un conjunto de direcciones de salto a las rutinas para cada señal posible). Dada la forma en que se activa la interrupción, en función del vector de interrupción, se llama a una función particular. Lamentablemente, no está claro dónde se llamará la memoria asociada con la variable, y dependiendo de la interrupción, esa memoria puede estar realmente dañada. Hay una forma de evitarlo, pero luego no puede aprovechar las instrucciones de ensamblaje int 0x80 existentes (que algunos sistemas todavía usan)
Esta es una pregunta muy antigua, pero creo que puedo mostrarte un buen truco que habría respondido a tu problema. No es necesario usar sigqueue o lo que sea.
También me desagrada el uso de variables globales, así que tuve que encontrar una forma inteligente, en mi caso, para enviar un ptr vacío (que luego puedes convertir a lo que sea que se adapte a tus necesidades).
En realidad puedes hacer esto:
signal(SIGWHATEVER, (void (*)(int))sighandler); // Yes it works ! Even with -Wall -Wextra -Werror using gcc
Entonces su signatario se vería así:
int sighandler(const int signal, void *ptr) // Actually void can be replaced with anything you want , MAGIC !
Usted podría preguntar: ¿Cómo obtener el * ptr entonces?
He aquí cómo: en la inicialización
signal(SIGWHATEVER, (void (*)(int))sighandler)
sighandler(FAKE_SIGNAL, your_ptr);
En tu funk sighandler :
int sighandler(const int signal, void *ptr)
{
static my_struct saved = NULL;
if (saved == NULL)
saved = ptr;
if (signal == SIGNALWHATEVER)
// DO YOUR STUFF OR FREE YOUR PTR
return (0);
}
No puede tener sus propios datos pasados al manejador de señal como parámetros. En cambio, tendrá que almacenar sus parámetros en variables globales. (Y sea muy, muy cuidadoso si alguna vez necesita cambiar esos datos después de instalar el manejador de señal).
Respuesta a editar 0: razones históricas. Las señales son realmente un diseño antiguo y realmente de bajo nivel. Básicamente, le dan al núcleo una sola dirección para un código máquina y le piden que vaya a esta dirección específica, si tal o cual cosa sucede. Estamos de vuelta en la mentalidad de "ensamblador portátil" aquí, donde los núcleos brindan un servicio básico sencillo y, independientemente de lo que razonablemente se pueda esperar del proceso del usuario, debe hacerlo solo.
Además, los argumentos habituales contra las variables globales no se aplican realmente aquí. El manejador de señal en sí es una configuración global, por lo que no existe la posibilidad relevante de tener varios conjuntos diferentes de parámetros especificados por el usuario para ello. (Bueno, en realidad no es completamente global, solo tiene hilos globales. Pero la API de subprocesos incluirá algún mecanismo para el almacenamiento local de subprocesos, que es justo lo que necesita en este caso).
Puede usar un manejador de señal que es un método de una clase. Entonces ese controlador puede acceder a los datos de miembros de esa clase. No estoy del todo seguro de lo que Python hace debajo de las coberturas aquí alrededor de la llamada a la señal C (), ¿pero debe volver a analizar los datos?
Me sorprendió que esto funcione, pero lo hace. Ejecuta esto y luego elimina el proceso desde otra terminal.
import os, signal, time
class someclass:
def __init__(self):
self.myvalue = "something initialized not globally defined"
signal.signal(signal.SIGTERM, self.myHandler)
def myHandler(self, s, f):
# WTF u can do this?
print "HEY I CAUGHT IT, AND CHECK THIS OUT", self.myvalue
print "Making an object"
a = someclass()
while 1:
print "sleeping. Kill me now."
time.sleep(60)
Un registro de manejador de señal ya es un estado global equivalente a las variables globales. Por lo tanto, no es una ofensa mayor usar variables globales para pasarle argumentos. Sin embargo, es un gran error (casi seguro comportamiento indefinido a menos que seas un experto) hacer cualquier cosa con un manejador de señal de todos modos. Si, en cambio, solo bloquea las señales y las consulta desde su ciclo de programa principal, puede evitar todos estos problemas.