管,叉和执行 – 父母与子女过程的双向沟通

我的操作系统类中的赋值要求我通过在同一程序上递归调用exec来构建二进制进程树。 目标是将一些任意任务拆分为单独的进程。 父母应该通过未命名的管道与孩子和父母进行交流。 我们的想法是父母将每个孩子的一半工作发送,并且这种情况会递归地继续,直到满足基本案例,其中传递给每个孩子的字符串长度<= 2.然后孩子处理这些数据并将结果发回通过管道给父母。

为了更好地理解双向通信如何与c中的管道一起工作,我在继续实际分配之前创建了以下简单程序。 父节点从不从子进程读取数据。 我期待输出……

在父母| 收到的消息:测试

相反,当我打印时,我得到……

在父母| 收到消息:

似乎buff是空的,而不是从子进程中读取。 有人可以解释我做错了什么和/或标准方式

  1. 写给父母的exec’d孩子
  2. 从exec’d孩子的父母那里读书
  3. 从exec’d孩子写回父母
  4. 从父母的执行孩子那里读书

我需要使用exec(),pipe(),fork()。 谢谢。

/** * ********************************* * two_way_pipes.c * ********************************* */ #include  #include  #include  #include  #include  #include  #include  #include  #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"); } } } 

更新

根据Jonathon的回答,我修改了传递给execvp的arg2数组到……

 char *argv2[] = {"two_way_pipes", "1", NULL}; execvp("two_way_pipes", argv2); 

这并没有解决问题。 父母仍然无法从客户端读回“测试”。 然而,为了回应乔纳森的回答和威廉的评论,我开始调整我的执行电话,并且出于某种原因将其更改为下面的线下节目。

 execl("two_way_pipes", "two_way_pipes", "1", NULL); 

我很乐意接受任何解释,解释为什么execvp调用不起作用,但execl调用。

除了Jonathon Reinhart 提到的问题之外,很可能对execv()的调用失败了。

要测试这个修改这些行

 execvp("two_way_pipes", argv2); _exit(0); 

成为

 ... #include  ... execvp("two_way_pipes", argv2); /* On sucess exec*() functions never return. */ perror("execvp() failed); /* Getting here means execvp() failed. */ _exit(errno); 

期待收到

 execvp() failed: No such file or directory 

要解决此更改

 execvp("two_way_pipes", argv2); 

成为

 execvp("./two_way_pipes", argv2); 

如果孩子不是exec*() ed那么这一行

 read(PARENT_READ, buff, 4); // should read "test" which was written by the child to stdout 

失败,反过来buff没有初始化,因此这一行

 fprintf(stderr, "in parent | message received: %s\n", buff); 

挑起未定义的行为。

要通过改变来解决这个问题,至少要正确地初始化buff

 char buff[5]; 

成为

 char buff[5] = ""; 

argv2的第一个条目应该是可执行文件的名称(就像传入的argv[0]

 char *argv2[] = {"two_way_pipes", "some random arg...", NULL}; execvp("two_way_pipes", argv2); 

execvp手册页 :

execv()execvp()execvpe()函数提供指向以null结尾的字符串的指针数组,这些字符串表示新程序可用的参数列表。 按照惯例,第一个参数应指向与正在执行的文件关联的文件名。 指针数组必须由NULL指针终止。

正如Jonathon Reinhart所说,你应该改变这句话:

 char *argv2[] = {"some random arg to make sure that argc == 2 in the child", NULL}; execvp("two_way_pipes", argv2); 

至:

 char *argv2[] = {argv[0], "some random arg...", NULL}; execvp(argv[0], argv2); 

然后它按预期工作:

 echo test | ./two_way_pipes in parent | message received: test 

在你的程序中你写了“two_way_pipes”,但它不在你的PATH中,所以你真的需要额外的./所以argv [0]然后是(“./two_way_pipes”)。