Pipe, Fork e Exec - Comunicação bidirecional entre pai e filho
Uma atribuição na minha classe Operating Systems requer que eu construa uma árvore de processos binários chamando exec de maneira recursiva no mesmo programa. O objetivo é dividir algumas tarefas arbitrárias em processos separados. O pai deve se comunicar com os filhos e os filhos com o pai apenas através de tubos não nomeados. A idéia é que o pai envie a cada filho metade do trabalho e isso continua recursivamente até que um caso base seja atendido, onde o comprimento da string passada a cada filho é <= 2. A criança então processa esses dados e envia os resultados de volta para o pai via pipes.
Para entender melhor como funciona a comunicação bidirecional com pipes em c, criei o seguinte programa simples antes de passar para a atribuição real. O pai nunca lê os dados do processo filho. Estou esperando a saída ...
no pai | mensagem recebida: teste
Em vez disso, quando eu imprimo eu recebo ...
no pai | mensagem recebida:
Parece que o buff está vazio e não está lendo o processo filho. Alguém por favor pode explicar o que estou fazendo de errado e / ou o modo padrão de
escrevendo para filho exec'd do pailendo de pai em criança exec'descrevendo de volta para o pai da criança exec'dlendo a criança exec em paiEu sou obrigado a usar exec (), pipe (), fork (). Obrigado.
/**
* *********************************
* two_way_pipes.c
* *********************************
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define PARENT_READ read_pipe[0]
#define PARENT_WRITE write_pipe[1]
#define CHILD_WRITE read_pipe[1]
#define CHILD_READ write_pipe[0]
#define DEBUGGING 1
int main(int argc, char **argv) {
char buff[5];
// in the child process that was exec'd on the orginal call to two_way_pipes
if(argc == 2) {
read(STDIN_FILENO, buff, 4); // this should read "test" from stdin
buff[4] = '\0';
fprintf(stdout, "%s\n", buff); // this should right "test" to stdout and be read by the parent process
// int the root process, the original call to two_way_pipes with no args
} else {
int pid;
int read_pipe[2];
int write_pipe[2];
pipe(read_pipe);
pipe(write_pipe);
pid = fork();
// parent process
if(pid > 0) {
close(CHILD_READ);
close(CHILD_WRITE);
write(PARENT_WRITE, "test", 4); // attempting to write this to the child
struct timeval tv;
fd_set readfds;
tv.tv_sec = 10;
tv.tv_usec = 0;
FD_ZERO(&readfds);
FD_SET(PARENT_READ, &readfds);
select(PARENT_READ + 1, &readfds, NULL, NULL, &tv);
if(FD_ISSET(PARENT_READ, &readfds)) {
read(PARENT_READ, buff, 4); // should read "test" which was written by the child to stdout
buff[4] = '\0';
close(PARENT_READ);
close(PARENT_WRITE);
fprintf(stderr, "in parent | message received: %s\n", buff); // "test" is not in buff
}
// child process
} else if(pid == 0) {
close(PARENT_READ);
close(PARENT_WRITE);
dup2(CHILD_READ, STDIN_FILENO);
dup2(CHILD_WRITE, STDOUT_FILENO);
close(CHILD_READ);
close(CHILD_WRITE);
char *argv2[] = {"some random arg to make sure that argc == 2 in the child", NULL};
execvp("two_way_pipes", argv2);
_exit(0);
// error forking child process
} else {
fprintf(stderr, "error forking the child\n");
}
}
}
Atualizar
Com base na resposta de Jonathon, modifiquei o array arg2 sendo passado para execvp para ...
char *argv2[] = {"two_way_pipes", "1", NULL};
execvp("two_way_pipes", argv2);
Isso não resolveu o problema. O pai ainda não conseguiu ler "teste" de volta do cliente. No entanto, em resposta à resposta de Jonathon e ao comentário de William, comecei a ajustar minha chamada de executivo e, por algum motivo, alterá-la para o programa de linha abaixo funcionou.
execl("two_way_pipes", "two_way_pipes", "1", NULL);
Eu aceito de bom grado todas as respostas explicando porque a chamada execvp não funcionaria, mas a chamada execl fez.