Заставить детей обрабатывать паузу до тех пор, пока родительский сигнал не получит выполнение задачи execl.

Я пытаюсь разработать простую железнодорожную симуляцию, следуя ответу на вопрос: заставьте детей обрабатывать ожидание, пока не получит сигнал родителя.

Моя задача: у меня ровно 5 процессов, представляющих поезда. Мне нужно создать эти 5 процессов (T1, T2, T3, T4 и T5) через fork()и приостановить каждый из них, пока все они не будут созданы. После этого родительский процесс отправит сигнал детям, и каждый ребенок будет использовать execl (т.е. execl(execl_path_name, CHILDETCONE, i, NULL);). После подачи сигнала родитель ждет, пока все дети выполнят свои задачи.

Я вполне понимаю функцию-обработчик, но мне не совсем понятны следующие моменты:

  1. Нужно ли мне вставлять execl внутри функции обработчика?

  2. Я не понимаю значение этого последнего цикла из ответа на предыдущий вопрос:

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

Это мой код:

#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);
}

1 ответ

Нужно ли мне вставлять execl внутри функции обработчика?

Нет. pause() вернется только после того, как процесс, в котором он вызывается, поймает сигнал, который вызывает выполнение функции обработки сигнала. execl Поэтому вызов может идти сразу после pause вызов. Я думаю, что было бы яснее в вашем случае.

Также обратите внимание, что POSIX стандартизирует список "async-signal-safe" функций, которые безопасны для вызова обработчиком сигнала, и что для обработчика небезопасно вызывать другие. execl в списке, но printf а другие функции потокового ввода-вывода - нет. Обработчики сигналов не должны вызывать printf, Вашему конкретному обработчику сигналов вообще ничего не нужно делать.

Кроме того, рассмотрите возможность использования sigsuspend() на месте pause(), так как первый даст вам больше контроля над тем, какие сигналы приводят в движение ваши поезда.

Я не понимаю значение этого последнего цикла из ответа на предыдущий вопрос:

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

wait() Функция инструктирует вызывающий процесс блокировать, пока один из его дочерних элементов не завершится. Цикл делает так много wait() вызывает, так как есть дочерние элементы, так что при отсутствии ошибок основная программа не продолжается до тех пор, пока все ее дочерние элементы не будут завершены.

Похоже, вы пытались достичь чего-то похожего, позвонив sleep() в петле с kill колл, но эта стратегия совершенно неверна. Во-первых, жду после каждого kill означает, что дети execl звонки будут разнесены по крайней мере sleep время, а это не то, что я понял, вы хотите. Во-вторых, вы не можете заранее знать, сколько времени потребуется детям, чтобы закончить, поэтому одной секунды, которую вы позволяете, может быть недостаточно при некоторых обстоятельствах. В-третьих, поскольку вы, похоже, ожидаете, что дети будут бегать очень быстро, одна секунда, вероятно, намного больше, чем вам нужно в большинстве случаев.

Другие вопросы по тегам