Использование каналов для связи с несколькими дочерними процессами, которые читают из stdin - PullRequest
0 голосов
/ 27 сентября 2018

Я изо всех сил пытаюсь правильно понять fork(), pipe() и execvp() и хотел бы получить руководство о том, где я ошибаюсь с этим кодом, и куда мне следует идти отсюда.Насколько я понимаю, если вы хотите запустить несколько процессов, вы fork() n раз используете оператор for, как показано ниже.Чтобы сохранить ссылку на каждый коммуникационный «канал» между родителем и многочисленными дочерними элементами, вы используете дескриптор файла 2D (например, fd[n][2]).Кроме того, чтобы разрешить связь двумя способами, вы используете 2 FD.При вызове exevp() он заменяет вызванный процесс на процесс, созданный execvp().

Итак, я создал простую программу, которая разветвляет 2 копии процесса, единственной целью которого является немедленное возвращение строки, отправленной родительским процессом.С этого момента он должен отправить сообщение дочернему процессу 0, затем дочернему процессу 1. Затем вечно ждет, пока что-то не будет сделано, чтобы завершить дочерний процесс или родительский процесс.Тем не менее, я сталкиваюсь с 2 проблемами.Во-первых, эта текущая программа останавливается на первом операторе read / printf в родительском процессе, и я получаю следующий результат, предлагающий мне ввести значения, которые ничего не делают, когда я нажимаю клавишу ввода.Я знаю, что эта ошибка возникает из-за моей программы execvp, поскольку удаление fgets и просто printf, ввод значения и выход работают, как и ожидалось.Однако мне нужно fgets, потому что я хочу иметь возможность вернуться к этому процессу и позже отправить ему больше сообщений.

Child 0
|         <--- Prompts me to enter value

Ожидается:

Child 0
Process 0 received: test message
Child 1
Process 1 received: test message

Вот моя основная программа:

int main () {
    char buff[50];
    int pipe_parent[2][2];
    int pipe_child[2][2];
    int pids[2];
    for (int i = 0; i < 2; i++) {
        char id[snprintf(NULL, 0, "%d", i) + 1];
        sprintf(id, "%d", i);
        char* prog[] = {"./test", id, NULL};

        if (pipe(pipe_parent[i]) == -1 || pipe(pipe_child[i]) == -1) {
            exit(1);
        }

        int pid = fork();
        if (pid > 0) {
            pids[i] = pid;
            close(pipe_child[i][0]);
            close(pipe_parent[i][1]);
            int in = pipe_child[i][1];
            int out = pipe_parent[i][0];
            write(out, "test message\n", 13); //hard coded but should use strlen + 1
            read(in, buff, 50);
            //The code below does not work and so probably the read above too
            printf("Child: %s", buff); //Does not print anything and starts waiting for use input here.
            //Inputting anything here does nothing
        } else if (pid == 0) { 
            print("Child %d", i);
            close(pipe_child[i][1]);
            close(pipe_parent[i][0]);
            dup2(pipe_child[i][0], STDIN_FILENO);
            dup2(pipe_parent[i][1], STDOUT_FILENO);
            close(pipe_child[i][0]);
            close(pipe_child[i][1]);
            execvp(prog[0], prog);
            exit(1); //Should not reach here unless error
        } //Should add error check here with else

    for (int i = 0; i < 2; i++) {
        int status;
        waitpid(pids[i], &status, 0);
    }

    return 0;
}

и моя другая программа, которая получает execvp 'd:

int main(int argc, char** argv) {
    char buff[50];
    while(fgets(buff, sizeof(buff), stdin) != NULL) {
        printf("Process &d received: %s", atoi(argv[1]), buff);
    }
    printf("Process %d closed", atoi(argv[1]));
    return 0;
}

Моя вторая проблема заключается в том, что, предполагая, что вышеуказанные программы работают, я не знаю, как работает связь с определенным процессом.Я хочу, чтобы программа работала так, чтобы она отправляла сообщение для обработки 0, затем 1, затем 0, .... и т. Д. (Или в любом другом порядке, указанном мной), пока что-то не будет сделано, чтобы остановить его.Я думаю, что код будет выглядеть примерно так для простого 0,1,0,1 ... code:

int counter = 0;
while(counter < 5) {
    for (int i = 0; i < 2; i++) {
        //setup out and in to be pipe_child/parent[i][0/1]
        write(out, "message", len);
        //read();
        //printf();
    }
    counter++;
}

Если бы я мог получить подсказку о том, как это работает, тобудет с благодарностью.

Редактировать: execl() до execvp()

...