简体   繁体   中英

Make children process in pause until receiving parent's signal to execute an execl task

I am trying to develop a simple railroad simulation following the answer to the question Make children process wait until receiving parent's signal .

My task: I have exactly 5 process representing trains. I need to create these 5 process (T1, T2, T3, T4, and T5) via fork() , and pause each one until all of them are created. After that the parent process will send a signal to the children, and each child will use an execl ( ie execl(execl_path_name, CHILDETCONE, i, NULL); ). After signaling, the parent waits for all the children to complete their tasks.

I quite understand the handler function, but I am not clear on these points:

  1. Do I need to insert my execl inside the handler function?

  2. I don't understand the significance of this last loop from the answer to the previous question:

     for (int i = 0; i < NUMBER_TRAINS; i++) { wait(NULL); } 

This is my code:

#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#include "accessory.h"


#define NUMBER_TRACKS 16
#define NUMBER_STATIONS 8
#define NUMBER_TRAINS 5

#define TRACKS_INITIALS "MA"
#define STATION_INITIALS "S"
#define SIZE 256
#define CHILDETCONE "childETCone"

void handler(int sig);

int main(int argc , char *argv[]) {
    pid_t pid;
    pid_t pid_array[NUMBER_TRAINS];

    char track_name[2];
    char track_number[2];
    int execl_return;
    char str[2];
    char * execl_path_name;

    memset(pid_array, 0, sizeof(pid_array));

    /* create the MAx file initialized to zero */
    for (int i = 1; i < (NUMBER_TRACKS + 1); i++) {
        memset(track_name, '\0', sizeof(track_name));
        memset(track_number, '\0', sizeof(track_number));
        strcpy(track_name, TRACKS_INITIALS);
        sprintf(track_number, "%d", i);
        strcat(track_name, track_number);
        create_track_file(track_name, "", SIZE);
    }

    execl_path_name = get_file_name(CHILDETCONE, "", SIZE);
    printf("path %p\n", execl_path_name);


    for(int i = 0; i < NUMBER_TRAINS; i++) {
        pid = fork();

        if (pid < 0) {
            perror("fork");
            exit(1);
        }
        if (pid == 0) { //child
            //sprintf(str, "%d", i+1);
            //execl_return = execl(execl_path_name, CHILDETCONE, i, NULL);
            signal(SIGUSR1, handler);
            pause();
            exit(0);
        }
        //parent
        pid_array[i] = pid;
    }

    for (int j = 0; j < NUMBER_TRAINS; j++) {
        kill(pid_array[j], SIGUSR1);
        sleep(1);
    }

    for (int i = 0; i < NUMBER_TRAINS; i++) {
        wait(NULL);
    }

    return 0;
}

void handler(int sig) {
    printf("printed from child [%d]\n", getpid());
    printf("signal [%d]\n", sig);
}

Do I need to insert my execl inside the handler function?

No. pause() will return only after the process in which it is called catches a signal that causes a signal-handling function to run. The execl call can therefore go just after the pause call. I think that would be clearer in your case.

Note, too, that POSIX standardizes a list of "async-signal-safe" functions that are safe for a signal handler to call, and that it is un safe for a handler to call others. execl is on the list, but printf and other stream I/O functions are not . Signal handlers should not call printf . Your particular signal handler does not need to do anything at all.

Additionally, consider using sigsuspend() in place of pause() , as the former will give you more control over which signals cause your trains to start.

I don't understand the significance of this last loop from the answer to the previous question:

 for (int i = 0; i < NUMBER_TRAINS; i++) { wait(NULL); } 

The wait() function instructs the calling process to block until one of its children terminates. The loop makes as many wait() calls as there are children, so that, in the absence of errors, the main program does not proceed until all its children have terminated.

It looks like you may have tried to achieve something similar by calling sleep() in the loop with the kill call, but that strategy is plain wrong. In the first place, waiting after each kill means that the children's execl calls will be spaced out by at least the sleep time, which is not what I understood you to want. In the second place, you cannot know in advance how long it will take the children to finish, so the one second you allow may not be enough under some circumstances. In the third place, since you seem to expect that the children will run very quickly, one second is probably much more than you need most of the time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM