1

The code doesn't work and it goes in loop. I think the error is in the gestore method, that is a handler for SIGCHLD signals. This is the first time I use a handler to capture SIGCHLD signals. This program continue to casually extracts from 0 to argv[1] until a number appears argv[1] times. If it's not clear you can test my old program that I put at the end of question. Can you help me finding the error?

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>

int a;
void gestore(int segnale);
int main(int argc, char * argv[]){
    int n = atoi(argv[1]), i, pid;
    int * vec;
    vec = malloc((n+1)*sizeof(*vec));
    memset (vec, 0, sizeof(*vec));
    char * newargv[] = {argv[0], argv[1] , NULL};
    for(i = 0; i < n; i++){
        pid = fork();
        if (pid == 0)
            execve("./throw-dice", newargv, NULL);
        signal(SIGCHLD, gestore);
        vec[WEXITSTATUS(a)]++;
    }
    while(vec[i] != n){
        for(i = 1; i < n+1 && vec[i] != n; i++){
            if(vec[i] != 0){
                pid = fork();
                if (pid == 0)
                    execve("./throw-dice", newargv, NULL);
                signal(SIGCHLD, gestore);
                vec[WEXITSTATUS(a)]++;
            }
        }
    }
    printf("The value %d is appeared %d times!\n", i, vec[i]);
    while (wait(&a) != -1);
    free(vec);
}

void gestore(int segnale){
    signal(segnale, SIG_IGN);
    waitpid(WAIT_ANY, &a, WNOHANG);
    signal(segnale, gestore);
}

My goal was to modify my old program (that works) changing the way I capture the exit status of childs. From syncronically with "wait" to asyncronically with a gestore method that handle SIGCHLD signals. This is my old program:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char * argv[]){
    int n = atoi(argv[1]), a, i, pid;
    int * vec;
    vec = malloc((n+1)*sizeof(*vec));
    memset (vec, 0, sizeof(*vec));
    char * newargv[] = {argv[0], argv[1] , NULL};
    for(i = 0; i < n; i++){
        pid = fork();
        if (pid == 0)
            execve("./throw-dice", newargv, NULL);
        wait(&a);
        vec[WEXITSTATUS(a)]++;
    }
    while(vec[i] != n){
        for(i = 1; i < n+1 && vec[i] != n; i++){
            if(vec[i] != 0){
                pid = fork();
                if (pid == 0)
                    execve("./throw-dice", newargv, NULL);
                wait(&a);
                vec[WEXITSTATUS(a)]++;
            }
        }
    }
    printf("The value %d is appeared %d times\n", i, vec[i]);
    while (wait(&a) != -1);
    free(vec);
}

//throw-dice.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char * argv[]) {
    int n, val;
    // Must have an argument
    if (argc < 2) {
        exit(-1);
    }
    // the 1st argument must be a positive number
    if ((n = atoi(argv[1])) <= 0) {
        exit(-1);
    }
    //  sleep(1); // sleep a bit
    srand(getpid()); // initialize the random seed with PID
    val = rand() % n + 1;
    printf("(PID=%d): got number %d\n", getpid(), val);
    exit(val);
}
  • 1
    What do you mean by "doesn't work"? Describe what you expect or want to have happen and what you see actually happen. As written, I would expect your main program to complete and exit before any child does, so you'll never see any signals. If that's not what you want, you need to say what you want. – Chris Dodd Dec 11 '17 at 17:01
  • I edited the code now to show you the original. It goes in loop and not ends. –  Dec 11 '17 at 17:05
  • 1
    Yes, your revised code has a likely infinite loop (`while (vec[i] !=n)` when you never change `vec[i]` to be other than the undefined value you get from malloc.) You need to ask a question about what you actually want to have happen to have any hope for an answer. What are you trying to do and why do you think you need a signal handler? – Chris Dodd Dec 11 '17 at 17:08
  • Edited once again. Now it should be all clear (?). –  Dec 11 '17 at 17:17
  • You've (unintentionally?) removed a call to `wait` inside your while loop. – William Pursell Dec 11 '17 at 17:25
  • It is intentionally because I don't wanna use the "wait". I wanna capture the signal and handle it with a method. –  Dec 11 '17 at 17:30
  • Then you need to use `sigwait` to have the main program wait for the signal handler instead. The basic problem you have is lack of synchronization between getting the child status in the global `a` and using that status in your main loop, so you read it before it was written. Even with `sigwait` you'll have race conditions when multiple children complete before your main loop continues. Why do you think you want a signal handler? – Chris Dodd Dec 11 '17 at 18:10
  • This is just an exercise of my teacher. By the way I don't know how to implement the sigwait you suggested me. Can you help me? –  Dec 11 '17 at 18:21
  • Check out this [link](https://stackoverflow.com/questions/6326290/about-the-ambiguous-description-of-sigwait) – TonyB Dec 11 '17 at 19:37

0 Answers0