c - 使用管道连接子进程

标签 c process pipe child-process

我想创建某种中文耳语(或电话)游戏。

我创建了一定数量的子进程,每个子进程必须更改字符串中的 1 个字母。父进程更改一个字母,然后第一个子进程获取父进程修改的字符串并再更改一个字母。第二个子项采用第一个子项修改的字符串(已更改 2 个字母)并再更改一个,依此类推。

因此,我想用管道链接父级和第一个子级以及每两个连续的子级。 问题是这对超过 3 个 child 不起作用。第三个 child 不从第二个 child 那里读,而是从 parent 那里读。你能告诉我我做错了什么吗?

    int nrch;
    nrch=(int) strtol(argv[2], (char **)NULL, 10);
    msg=argv[3];
    printf("Parent: erhalten: %s\n", msg);
    int i=0;
    msg=modify(argv[3],nrch);
    printf("Parent: weiter: %s\n", msg);
    pid_t pids[10];
    int fd[2];
    int fdold[2];

    if (pipe(fdold) == -1) {
        error("Can't create the pipe");
    }

    /* Start children. */
    for (i = 0; i < nrch; ++i) {
        if (pipe(fd) == -1) {
            error("Can't create the pipe");
        }
        if ((pids[i] = fork()) < 0) {
                error("Can't fork process");
        } 
        else if (pids[i] == 0) {

            //dup2(fd[0], 0);
            if(i==0){
                close(fdold[1]);
                close(fd[0]);
                read(fdold[0],msg,sizeof(msg));
                printf("child%d: erhalten: %s\n", (i+1), msg);
                    msg=modify(msg,i);
                printf("child%d: weiter: %s\n", (i+1), msg);
                write(fd[1],msg,sizeof(msg));   
                exit(0);
            }
            else if(i==(nrch-1)){
                close(fdold[1]);
                read(fdold[0],msg,sizeof(msg));
                printf("child%d: erhalten: %s\n", (i+1), msg);
                    msg=modify(msg,i);
                printf("child%d: weiter: %s\n", (i+1), msg);
                printf("child%d: Ende: %s\n", (i+1), msg);

                    exit(0);
            }
            else{
                close(fdold[1]);
                close(fd[0]);
                read(fdold[0],msg,sizeof(msg));

                printf("child%d: erhalten: %s\n", (i+1), msg);
                    msg=modify(msg,i);
                printf("child%d: weiter: %s\n", (i+1), msg);

                write(fd[1],msg,sizeof(msg));   
                exit(0);
            }
        }
        else{
            if(i!=0){
                close(fd[1]);
            }
            else{
                write(fdold[1], msg,sizeof(msg));

            }
            if(i>1){
                close(fdold[0]);
            }
        }
        pid_t wpid;
        int status;
        wpid = wait(&status);
        memcpy(fdold,fd,(sizeof(int)*2));
    }   
    close(fd[0]);

最佳答案

我认为您的 child 代码过于复杂。您似乎还在循环的每次迭代中从父级写入。

您正确地为每个子进程创建了一个管道,但我没有看到一种将管道的一侧从一个兄弟进程传递到下一个兄弟进程的机制,这是父进程需要管理的。

在下面的代码中,我在父级中使用 prev_in 将管道的读取端最初从父级传递到第一个子级,然后从兄弟级传递到兄弟级,最后父级使用它作为其管道的读取端。

我没有检查此代码是否存在任何可能存在的缓冲区溢出问题,我只查看了文件描述符管理问题,您可能应该注意检查其他错误。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char *modify (char *word, int num)
{
  printf ("Modify `%s', (%d)\n", word, num);
  word [num] = 'x';
  return word;
}

void
whisper (int id, int in, int out)
{
  char msg [100];

  read(in, msg, sizeof(msg));
  printf("child%d: heard: %s\n", id, msg);
  modify (msg, id);
  printf("child%d: says: %s\n", id, msg);
  write(out, msg, sizeof(msg));
}

void
start_whisper (int in, int out, char *msg)
{
  char buf [100];

  printf ("Parent, starting a whisper with `%s'\n", msg);
  write(out, msg, strlen (msg) + 1); /* Also send the NUL.  */

  read(in, buf, sizeof(buf));
  printf("Parent, heard back: %s\n", buf);
}

int
main (int argc, char *argv [])
{
  int nrch, i;
  char *msg;
  pid_t pids[10];

  nrch=(int) strtol(argv[2], (char **)NULL, 10);
  printf ("Number of children = %d\n", nrch);

  msg = argv[3];
  printf("Parent: original message: %s\n", msg);

  if (nrch == 0 || nrch > strlen (msg))
    error ("Invalid number of children");

  msg = modify (msg, nrch);
  printf("Parent: will start by saying: %s\n", msg);

  int fdold[2];
  int prev_in, parent_in, parent_out;

  if (pipe(fdold) == -1) {
    error("Can't create the pipe");
  }
  printf ("Parent Read: %d, Write: %d\n", fdold [0], fdold [1]);

  parent_in = fdold [0];
  parent_out = fdold [1];

  /* Start children. */
  prev_in = parent_in;
  for (i = 0; i < nrch; ++i)
    {
      int fd[2];
      if (pipe (fd) == -1) {
        error ("Can't create the pipe");
      }
      if ((pids[i] = fork()) < 0) {
        error("Can't fork process");
      }
      else if (pids[i] == 0)
        {
          /* Child.  */
          int my_in, my_out;

          close (fd [0]); /* The sibling read handle, this becomes prev_in
                             and is passed to the next sibling.  */
          close (parent_out); /* The parent write handle, only the parent
                                 wants to hold this, every child will
                                 close it.  */

          my_in = prev_in;
          my_out = fd [1];

          whisper (i, my_in, my_out);
          exit (0);
        }
      else
        {
          /* Parent.  */
          close (prev_in); /* The PREV_IN was passed the child we just
                              created, we no longer need this.  */
          prev_in = fd [0]; /* The read handle from the pipe we just made
                               will be passed to the next sibling.  */
          close (fd [1]); /* The write handle from the pipe we just made
                             was grabbed by the child we just made, we no
                             longer need this.  */
        }
    }

  start_whisper (prev_in, fdold [1], msg);

  pid_t wpid;
  int status;
  wpid = wait(&status);

  return 0;
}

关于c - 使用管道连接子进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23497555/

相关文章:

c++ - 编译器错误与链接器错误?

c - 想在 C 中为一个函数实现超时

linux - 获取后台进程的退出代码

linux - 维护跨不同执行的 FIFO 可读

c# - 如何将数据行中的所有单元格复制到 session 中?

c - 为什么它以十六进制表示法这样显示?

windows - 使用CMD根据其描述查找Windows进程

linux - Ubuntu 16.04 显示孤儿进程的父 ID 4147

.net - 在同一网络上的不同计算机上运行的进程之间进行通信的推荐方式

c - 识别程序 "before"和 "after"管道中的程序来自同一个 "toolset"