es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Error principal cuando se envían múltiples señales.

Tengo este problema:

He creado un programa en C en el que el proceso principal crea algunos procesos hijos y, después de un tiempo, estos pueden enviar una señal al proceso principal:

La señal se envía con este código:

kill(getppid(), SIGUSR1);

Y el proceso principal, en el bucle while, está esperando el mensaje SIGUSR1…

Todo va bien, pero si aumento el número de hijos y, automáticamente, aumenta la posibilidad de tener más señales al mismo tiempo, el programa se bloquea y muestra el mensaje:

Señal definida por el usuario 1

El código principal es el siguiente:

void signalHandler(int sig, siginfo_t* info, void* vp) {
    if (sig == SIGUSR1) {
        printf("SIGUSR1 ha llegado\n");
    } else if (sig == SIGUSR2) {
        printf("SIGUSR2 ha llegado\n");
    }
}

int main(int argc, char const *argv[]) {
    struct sigaction action, old_action;

    memset(&action, 0, sizeof(struct sigaction));
    action.sa_sigaction = signalHandler;
    sigemptyset(&action.sa_mask);
    action.sa_flags = SA_RESTART | SA_NODEFER;

    while (1) {
        sigaction(SIGUSR1, &action, &old_action);
        sigaction(SIGUSR2, &action, &old_action);
    }
}

Creo que el problema es que la señal se envía cuando el proceso principal aún está trabajando en la señal anterior… pero ¿cómo puedo solucionar esto?

Muchas gracias.

Tags:  , ,

Answer

  1. Avatar for davy.ai

    El problema al que te enfrentas está relacionado con el hecho de que cuando se reciben múltiples señales al mismo tiempo, pueden sobrescribirse entre sí y causar un bloqueo. Una posible solución a este problema es utilizar una cola de señales.

    Cuando se recibe una señal, en lugar de procesarla de inmediato, el manejador de señales debe agregar la señal a una cola. El proceso principal puede luego procesar las señales una a una desde la cola. Esto asegura que no se pierdan ni se sobrescriban señales, y también permite que el proceso principal procese las señales a su propio ritmo.

    Para implementar una cola de señales, puedes utilizar una estructura de datos como una lista enlazada o un búfer circular. Cada vez que se recibe una señal, se agrega al final de la cola. El proceso principal puede luego desencolar y procesar las señales desde el frente de la cola.

    Aquí tienes un ejemplo de implementación utilizando una lista enlazada:

    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    
    typedef struct Node {
        int signal;
        struct Node* next;
    } Node;
    
    Node* head = NULL;
    Node* tail = NULL;
    
    void enqueue(int signal) {
        Node* newNode = (Node*) malloc(sizeof(Node));
        newNode->signal = signal;
        newNode->next = NULL;
    
        if (head == NULL) {
            head = tail = newNode;
        } else {
            tail->next = newNode;
            tail = newNode;
        }
    }
    
    int dequeue() {
        if (head == NULL) {
            return -1; // la cola está vacía
        }
    
        int signal = head->signal;
    
        Node* temp = head;
        head = head->next;
        free(temp);
    
        if (head == NULL) {
            tail = NULL;
        }
    
        return signal;
    }
    
    void signalHandler(int sig, siginfo_t* info, void* vp) {
        enqueue(sig);
    }
    
    int main(int argc, char const *argv[]) {
        struct sigaction action, old_action;
    
        memset(&action, 0, sizeof(struct sigaction));
        action.sa_sigaction = signalHandler;
        sigemptyset(&action.sa_mask);
        action.sa_flags = SA_RESTART | SA_NODEFER;
    
        while (1) {
            sigaction(SIGUSR1, &action, &old_action);
            sigaction(SIGUSR2, &action, &old_action);
    
            // procesar todas las señales de la cola
            while (head != NULL) {
                int signal = dequeue();
    
                if (signal == SIGUSR1) {
                    printf("SIGUSR1 ha llegado\n");
                } else if (signal == SIGUSR2) {
                    printf("SIGUSR2 ha llegado\n");
                }
            }
        }
    }
    

    En esta implementación, la función enqueue() agrega una nueva señal al final de la lista enlazada, mientras que la función dequeue() elimina y devuelve la primera señal de la lista. El manejador de señales simplemente encola la señal recibida, y el proceso principal desencola y procesa las señales a medida que llegan.

    Con esta implementación, puedes manejar de manera segura múltiples señales sin el riesgo de sobrescribir o perderlas.</signal.h></stdlib.h></stdio.h>

Comments are closed.