Puedo proporcionar/pasar argumentos a la señal del controlador?

/* Signal handling */
struct sigaction act;
act.sa_handler = signal_handler;
/* some more settings */

Ahora, controlador se parece a esto:

void signal_handler(int signo) {
    /* some code */
}

Si quiero hacer algo especial, es decir, eliminar archivos temporales, puedo proporcionar los archivos como un argumento para este controlador?

Editar 0: Gracias por las respuestas. Nosotros en general, evitar y desalentar el uso de variables globales. Y en este caso, Si usted tiene un programa enorme, las cosas pueden ir mal en diferentes lugares y usted podría tener que hacer un montón de limpieza. ¿Por qué fue el API diseñado de esta manera?

InformationsquelleAutor hari | 2011-08-07

6 Comentarios

  1. 53

    Usted no puede tener los datos de su propia pasa a la señal del controlador de parámetros. En su lugar tendrá que guardar sus parámetros en variables globales. (Y ser muy, muy cuidadoso si alguna vez necesita cambio los datos después de instalar el controlador de señal).

    Respuesta a editar 0: razones Históricas. Las señales son un muy viejo y muy bajo nivel de diseño. Básicamente, usted está simplemente dado que el núcleo de una sola dirección a código máquina y pidiéndole que vaya a esta dirección específica si tal y tal cosa sucede. Estamos de vuelta en el «portátil ensamblador» mentalidad de aquí, donde los granos proporcionan un bajo coste de referencia del servicio, y cualquiera que sea el proceso de usuario se puede razonablemente esperar que por sí mismo, debe hacer de sí mismo.

    Además, los habituales argumentos en contra de las variables globales en realidad no se aplican aquí. El manejador de señal es una configuración global, por lo que no es relevante la posibilidad de tener varios conjuntos de usuario los parámetros especificados para todo. (Bueno, en realidad no es enteramente de los mundiales, pero sólo hilo-global. Pero el roscado API se incluyen algún mecanismo para el almacenamiento local de subprocesos, que es justo lo que necesita en este caso).

    • Los manejadores de señales no son per-hilo. Cambiar el controlador de la señal se aplica a todos los hilos.
    • A la derecha. Pero aún así tiene sentido querer el manejador de señal a reaccionar para que el hilo es la manipulación, que es lo TLS puede lograr.
    • En realidad no tengo claro si el acceso TLS desde un manejador de señal es válida. Con glibc/NPTL es casi seguro que no válido en general, debido a que una señal puede ser entregado inmediatamente después de que el hilo está creado, pero antes de que el control se pasa a la función de arranque, mientras que el hilo de la copia de TLS todavía está inicializado. Si tienes cuidado de tener señales bloqueadas en este momento, puede estar bien, pero es una práctica dudosa todavía…
    • Por el camino, aun sin TLS, hay una manera para identificar el hilo que el manejador de señal se está ejecutando en un asíncrona de la señal de forma segura: &errno es único para cada hilo! Sin embargo, creo que este puede no ser seguro en glibc/NPTL por la misma razón que acabamos de describir. Si no, estoy bastante seguro de que es una conformidad error, pero es probable que no sea lo suficientemente raro carrera para pasar desapercibido…
    • Los manejadores de señales puede ser en cada subproceso. POSIX proporciona la funcionalidad que usted puede utilizar para enviar señales a los hilos individuales dentro del mismo proceso.
    • Sus dos frases que no están relacionados. Sí, usted puede enviar una señal a un hilo en concreto, pero el controlador de estado global. No hay manera de establecer diferentes controladores en una base por subproceso corto de la implementación de su propio despachador como el principal gestor de señal, y esto es tanto (1) dificultad para coordinar entre las diferentes bibliotecas que puede que necesite establecer una per-hilo controlador, y (2) técnicamente imposible sin la UB, porque no hay COMO modo seguro para un manejador de señal para determinar el hilo que se ejecuta en.

  2. 16

    Un manejador de señal de inscripción es ya un estado global equivalente a variables globales. Así que no hay mayor ofensa para el uso de variables globales para pasar argumentos a ella. Sin embargo, es un gran error (casi seguramente un comportamiento indefinido a menos que seas un experto!) para hacer cualquier cosa, desde un manejador de señal de todos modos. Si, en lugar de simplemente bloquear las señales y encuesta para ellos desde el bucle principal del programa, usted puede evitar todos estos problemas.

    • Gracias por la respuesta. No estoy del todo seguro de lo que aquí se sugiere. Por favor puede elaborar? Mi preocupación es, digamos que tengo 5 funciones en un programa y que algo malo puede suceder en cualquiera de ellos, ¿cómo puedo evitar tener declarar global variables a tener cuidado de limpiar?
    • A menos que usted es un experto con las señales, es muy peligroso hacer cualquier cosa, desde un manejador de señal. En lugar de eso sólo podría utilizar el manejador de señal para guardar un indicador de que la señal que pasó, y comprobar desde varios puntos exteriores a la señal del controlador, o usted podría bloquear las señales y el uso sigpending o sigwait a la encuesta para las señales.
    • Wow, esto es completamente nuevo para mí. He visto el código haciendo limpia como los archivos temporales de la eliminación o el niño el proceso de limpiar antes de que el principal programa de terminar. También al decir de verificación para banderas, ¿cómo puede funcionar si usted consigue SIGTERM? No de su programa de terminar de inmediato si no se controla que en el controlador? ¿Por qué es dangerous hacer las cosas dentro de un controlador?
    • Un manejador de señal que puede interrumpir el programa en cualquier momento. Esto significa que, a menos que usted haya tenido el cuidado de asegurarse de que esto no puede suceder, podría funcionar con varios objetos de datos que quiere trabajar en el estado incoherente. Por ejemplo, los punteros de búfer en el interior de un FILE sólo podría ser parcialmente actualizado, o la lista enlazada de abrir FILEs podría tener un mitad-se inserta en la mitad de-elemento eliminado en parte vinculada. O en el interior de malloc estructuras de datos podría tener la mitad-libera la memoria se hace referencia… Si el manejador de señal de las llamadas funciones que dependen de ese estado de ser coherente, muy mal las cosas van a suceder!
    • POSIX se ocupa de estas cuestiones mediante la definición de un conjunto de funciones que son «async-señal-segura», lo que significa que puede ser llamado de los manejadores de señal sin ningún tipo de preocupaciones. Cualquier otra función, que es «async-señal-inseguro», no es legal para llamar desde un manejador de señal, a menos que usted puede estar seguro de que el manejador de señal no podría haber «interrumpido» cualquier otro async-señal-inseguro función.
    • Gracias por la información y explicación. Yo también he leído un poco más acerca de los controladores de señal.
    • Por cierto, uno de los clásicos favoritos de «seguro» para el uso de manejadores de señal es abrir una tubería a ti mismo, y almacenar los descriptores de archivo en algún lugar mundial. El manejador de señal puede escribir a la tubería (esto es seguro) y usted puede esperar para la entrada de la tubería en su principal select/poll bucle junto con otros descriptores de archivo que usted está esperando para la entrada de.
    • Oh, está bien. No estoy seguro si entiendo lo que quieres transmitir, pero gracias. Voy a buscar en la web y tratar de entenderlo. Agradezco su ayuda.
    • Me acaba de publicar una pregunta de seguimiento: stackoverflow.com/questions/6971201/…
    • hay signalfd() en Linux que hace exactamente eso. Sigue siendo una buena idea. Pocas personas consideran el uso de tubos para comunicarse en de un proceso. Facilita la comunicación entre hilos mucho más sencillo y explícito.

  3. 5

    Esta es realmente una pregunta vieja, pero creo que puede mostrar un buen truco que habría respondido a su problema.
    No hay necesidad de utilizar sigqueue o lo que sea.

    También me disgusta el uso de variables globales así que tuve que encontrar una manera inteligente, en mi caso, para enviar un vacío ptr (que luego puede emitidos a lo que se adapte a su necesidad).

    Realmente puede hacer esto :

    signal(SIGWHATEVER, (void (*)(int))sighandler); //Yes it works ! Even with -Wall -Wextra -Werror using gcc

    Entonces su sighandler tendría este aspecto :

    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 su sighandler func
    :

    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);
    }
    • Buen truco, pero por desgracia es no definida por el estándar. Ver 6.3.2.3(8): if a converted pointer is used to call a function whose type is not compatible with the referenced type, the behavior is undefined.
  4. 1

    Almacenar los nombres de los archivos en una variable global y, a continuación, acceder a ella desde el controlador. El manejador de señal de devolución de llamada sólo se pasa un argumento: el ID de la señal real que causó el problema (por ejemplo, SIGINT, SIGTSTP)

    Editar 0: «debe haber una sólida razón para no permitir que los argumentos para el controlador.» <– Hay un vector de interrupción (básicamente, un conjunto de saltar las direcciones de las rutinas para cada posible de la señal). Dada la forma en que la interrupción se activa, basada en el vector de interrupción, un particular se llama a la función. Por desgracia, no queda claro de dónde la memoria asociada con la variable será llama, y dependiendo de la interrupción que la memoria puede en realidad ser dañado. Hay una manera de conseguir alrededor de él, pero entonces no se puede aprovechar la int 0x80 instrucciones de montaje (que algunos sistemas todavía uso)

  5. 0

    Puede utilizar un manejador de señal, que es un método de una clase. A continuación, el controlador puede acceder a los datos de los miembros de esa clase. No estoy totalmente seguro de lo que Python no bajo las cubiertas aquí todo el C de la señal() la llamada, pero debe ser re-diseño de datos?

    Yo estaba sorprendida de que esto funciona, pero lo hace. Ejecutar este y luego matar el proceso desde otro 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)
    • La pregunta era acerca de C … a Pesar de Python más probable es que se acuerda de la señal en algún lugar de procesar más tarde, tan pronto como sea posible (es peligroso hacer las cosas dentro de manejadores de señal). Posiblemente el uso de una variable global.

Dejar respuesta

Please enter your comment!
Please enter your name here