Foros del Web » Programación para mayores de 30 ;) » C/C++ »

*TUTORIAL* Manejo de señales bajo ambientes UNIX

Estas en el tema de *TUTORIAL* Manejo de señales bajo ambientes UNIX en el foro de C/C++ en Foros del Web. Hola que tal, ya tiene un rato que no me aparesco en estos foros asi que me decidí a leer algunos posts. En general me ...
  #1 (permalink)  
Antiguo 25/03/2011, 19:28
 
Fecha de Ingreso: octubre-2010
Ubicación: Edo. de México
Mensajes: 94
Antigüedad: 14 años, 2 meses
Puntos: 9
*TUTORIAL* Manejo de señales bajo ambientes UNIX

Hola que tal, ya tiene un rato que no me aparesco en estos foros asi que me decidí a leer algunos posts. En general me encontre con que muchos tienen problemas con algunos temas fuertes de C y C++, asi que me he propuesto a realizar tutoriales de algunos de estos temas como:
* Manejo de señales
* Sockets
* Manejo de memoria dinámica
* Uso de fork para la creación de procesos hijos
y algún otro tema que se me vaya ocurriendo.

Sin mas preambulos, a continuación les muestro la forma en que podemos utilizar las señales de UNIX en nuestros propios códigos. Espero les sea de ayuda.



En UNIX hay distintas señales correspondientes a diferentes eventos que ocurren en el sistema, por ejemplo, cuando estamos ejecutando algun proceso (programa) en primer plano y oprimimos la combinación CTRL + C, enviamos la señal SIGINT (señal de interrupción) al proceso en cuestion, y de este modo lo detenemos.

Estas señales pueden ser utilizadas en nuestro programas. Imaginemos que tenemos un programa que abre diversos archivos y trabaja con ellos dentro de un bucle infinito, bueno pues, ahora imaginemos que queremos detener ese programa pero como buenos programadores queremos que los archivos que abrimos en este programa se cierren antes de la finalización del proceso. Precisamente para este tipo de situaciones podemos utilizar señales como SIGINT, asi al momento de oprimir CTRL + C, podemos hacer que el programa no solo cierre, si no que ANTES cierre todos los archivos que tenia abiertos.

A continuacion agrego una lista con las distintas señales manejadas en UNIX, descritas en el estandar POSIX.1-1990.

Código:
       Signal     Value     Action   Comment
       ──────────────────────────────────────────────────────────────────────
       SIGHUP        1       Term    Hangup detected on controlling terminal
                                     or death of controlling process
       SIGINT        2       Term    Interrupt from keyboard
       SIGQUIT       3       Core    Quit from keyboard
       SIGILL        4       Core    Illegal Instruction
       SIGABRT       6       Core    Abort signal from abort(3)
       SIGFPE        8       Core    Floating point exception
       SIGKILL       9       Term    Kill signal
       SIGSEGV      11       Core    Invalid memory reference
       SIGPIPE      13       Term    Broken pipe: write to pipe with no
                                     readers
       SIGALRM      14       Term    Timer signal from alarm(2)
       SIGTERM      15       Term    Termination signal
       SIGUSR1   30,10,16    Term    User-defined signal 1
       SIGUSR2   31,12,17    Term    User-defined signal 2
       SIGCHLD   20,17,18    Ign     Child stopped or terminated
       SIGCONT   19,18,25    Cont    Continue if stopped
       SIGSTOP   17,19,23    Stop    Stop process
       SIGTSTP   18,20,24    Stop    Stop typed at tty
       SIGTTIN   21,21,26    Stop    tty input for background process
       SIGTTOU   22,22,27    Stop    tty output for background process

       The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
Antes de continuar con esto de las señales combiene explicar otro aspecto, los PIDs (Process ID).

En UNIX, todos los procesos (incluso los del sistema) tienen un identificador llamado PID. Este identificador es el número asignado por el sistema y podemos conocerlo mediante la funcion getpid(), para utilizar esta función debemos incluir las librerias <sys/types.h> y <unistd.h>.

Para poder modificar el comportamiento de las señales de UNIX es necesario utilizar la libreria <signal.h>. Dentro de esta libreria podemos encontrar la función "signal". Esta función recibe dos parametros, el primer parametro que recibe es la señal sobre la que tendra efecto (cabe mencionar que las señales no son mas que constantes enteras, asi que basta con saber el número de la señal o el nombre de la constante) y el segundo parametro es el apuntador a una función, en la cual se define el comportamiento nuevo de la señal o señales. Un ejemplo sencillo podría ser el siguiente.

Código c:
Ver original
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <signal.h>
  4. #include <sys/types.h>
  5. #include <unistd.h>
  6.  
  7. void misAcciones(int sig);
  8.  
  9. int main(void){
  10.     signal(SIGINT, misAcciones);
  11.     while(1) sleep(1);
  12. }
  13.  
  14.  
  15.  
  16.  
  17. void misAcciones(int sig){
  18.     switch(sig){
  19.         case SIGINT:
  20.             printf("Saliendo del programa\n");
  21.             exit(0);
  22.         break;
  23.     }
  24. }


La forma en que se deben declarar las funciones utilizadas para modificar el comportamiento de las señales esta mostrada en el ejemplo. Debe ser una función que no regrese dato alguno, y que reciba un único parámetro de tipo entero.

Tambien es importante que al llamar esta función sea de la siguiente forma
Código:
signal(SIGINT, misAcciones);
es decir, sin "ningun" parámetro y sin paréntesis. Ya que la función "signal" te pide un APUNTADOR a una función.

La función "signal" manda automáticamente como parametro la señal capturada a "misAcciones", en este caso la recibe en la variable "sig". Por lo que si la funcion recibida es "SIGINT" mostrará en pantalla el mensaje "Saliendo del programa" y ejecutara un exit(0).



Espero esto les de una buena idea de como manejar señales en sus programas, por último les pongo un programa que hize para mostrar el uso de señales y de la funcion fork. Si tienen dudas haganmelas saber. Salu2


Código c:
Ver original
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <signal.h>
  4. #include <sys/types.h>
  5. #include <unistd.h>
  6.  
  7. #define MAX_HIJOS 3
  8. #define INTERVALO 5
  9.  
  10.  
  11. void temp(int sig);
  12. void misAcciones(int sig);
  13.  
  14. int hijo[MAX_HIJOS];
  15.  
  16.  
  17. int main (void){
  18.   int ppid = 0;
  19.   int contador = 0;
  20.   int pidActual;
  21.  
  22.  
  23.   ppid = getpid();  
  24.   printf("Padre -> %i\n", ppid);
  25.   for(contador = 0; contador < MAX_HIJOS ; contador++){
  26.     pidActual = fork();
  27.  
  28.     if(pidActual < 0) return -1;
  29.  
  30.  
  31.     if(pidActual == 0){
  32.       switch(contador){
  33.       case 0:
  34.     signal(30, misAcciones);
  35.     printf("HIJO[0] -> %i\n", getpid());
  36.     while(1) pause();
  37.     break;
  38.       case 1:
  39.     signal(10, misAcciones);
  40.     printf("HIJO[2] -> %i\n", getpid());
  41.     while(1) pause();
  42.     break;
  43.       case 2:
  44.     signal(16, misAcciones);
  45.     printf("HIJO[3] -> %i\n", getpid());
  46.     while(1) pause();
  47.     break;
  48.       }
  49.     }
  50.  
  51.     hijo[contador] = pidActual;
  52.   }
  53.  
  54.  
  55.   if(signal(SIGALRM, temp) == SIG_ERR)
  56.     printf("No fue posible cambiar acción a SIGALRM\n");
  57.  
  58.  
  59.   alarm(INTERVALO);
  60.   while(1) pause();
  61. }
  62.  
  63.  
  64. void temp(int sig){
  65.   printf("Temp: Me llamo %i\n", getpid());
  66.   kill(hijo[0], 30);
  67.   kill(hijo[1], 10);
  68.   kill(hijo[2], 16);
  69.   alarm(INTERVALO);
  70. }
  71.  
  72. void misAcciones(int sig){
  73.   int i, j;
  74.   switch(sig){
  75.   case 30:
  76.     for(i = 0; i < 300000; i++);
  77.     printf("Me llamo %i, con la senial %i\n", getpid(), sig);
  78.     break;
  79.   case 10:
  80.     printf("Me llamo %i, con la senial %i\n", getpid(), sig);
  81.     break;
  82.   case 16:
  83.     for(i = 0; i < 100000; i++)
  84.       for(j = 0; j < 100000; j++);
  85.     printf("Me llamo %i, con la senial %i\n", getpid(), sig);
  86.     break;
  87.   }
  88. }

Última edición por Trovaz; 25/03/2011 a las 19:40 Razón: dedaso xD

Etiquetas: manejo, señales, unix, tutoriales
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta

SíEste tema le ha gustado a 4 personas




La zona horaria es GMT -6. Ahora son las 22:10.