【问题标题】:Create child using fork() inside for loop to run execlp()在 for 循环中使用 fork() 创建子项以运行 execlp()
【发布时间】:2012-11-29 21:32:08
【问题描述】:

我正在编写一个运行 Linux 命令的 C 程序,例如:

$ cat /etc/passwd |切-f1 -d:|排序

这个想法是使用 fork() 创建子进程以使用 execlp() 运行命令。我计划使用两个管道进行通信并使用 dup() 引导输入输出。

输出错误:

ls -l | wc -c on 命令返回 1746 程序返回 1761

代码(编辑以反映建议):

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <limits.h>

int main()
{
  int i,fd1[2],status,listpid[2];
  pid_t child;
  pipe(fd1);

  for(i=0; i< 2; i++)
  {
    printf("\ncreating child\n");
    if((child = fork()) == -1)
    {
      perror("fork");
      exit(EXIT_FAILURE);

    }
    else if(child == 0)
    {
      if(i == 0)
      {
    close(1); dup(fd1[1]);
    close(fd1[0]);
    close(fd1[1]);
    printf("\nrunning ls -l\n");
    fflush(stdout);
    execlp("ls","ls","-l", (char *)NULL);
    exit(EXIT_SUCCESS);

      }
      else if(i == 1)
      {
    close(0); dup(fd1[0]);
    close(fd1[1]);
    close(fd1[0]);
    printf("\nrunning wc -c\n");
    fflush(stdout);
    execlp("wc","wc","-c", (char *)NULL);
    exit(EXIT_SUCCESS);

      }

    }
    else
    {
      listpid[i]=child;
    }

  }

  close(fd1[0]);
  close(fd1[1]);

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

    if(WIFEXITED(status)) 
    {
      printf("\n[%d] TERMINATED (Status: %d)\n",listpid[i], WEXITSTATUS(status));

    }

  }
  exit(EXIT_SUCCESS);

}

【问题讨论】:

标签: c linux for-loop exec fork


【解决方案1】:

首先你不能在循环中 waitpid ——如果 ls 的输出足够大,它会填满管道,所以在有人读到它之前它不会完成:你必须在 for 循环之后等待两个孩子. 其次——只要管道的另一端打开,wc 就会继续运行,也就是说,您也必须关闭父管道中的管道。

【讨论】:

  • 这样吗? if((child == 0) { } else { if (i == 0) { close(fd1[1]); } else if(i%2 != 0) { close(fd1[0]); } }
  • @user1863673:一般来说,如果你dup()dup2()pipe()返回的一对描述符中的一个,你需要关闭both@返回的描述符987654324@。可能有例外;他们很少。
  • 仍然没有解决问题。
【解决方案2】:

更新后,两个子进程的行为正常。但是,您仍然需要添加:

close(fd1[0]);
close(fd1[1]);

在启动子进程的 for 循环和收集退出状态的 for 循环之间。

因为管道的写端仍然是打开的,wc 没有收到 EOF,所以它没有终止,所以你的进程无限期地等待。

【讨论】:

  • 非常感谢。这解决了悬挂问题。但是输出仍然是错误的。
  • 输出有什么问题?您还记得标准输出是通过管道发送的,因此您的诊断打印被发送到wc -c,与在shell 中运行ls -l | wc -c 得到的字符数相比,字符数增加了? stderr 的存在是有原因的;这样就不会将诊断信息发送到管道中而引起混淆。如果您将printf( 全局更改为fprintf(stderr,,那么您程序的计数与shell 从ls -l | wc -c 获得的计数一致。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-20
  • 2017-09-01
  • 1970-01-01
  • 2020-07-23
  • 1970-01-01
  • 2022-07-07
相关资源
最近更新 更多