我正在用c编写一个管道模拟.当有多个‘|’时,它崩溃了,其他进程必须读取前一个进程的输出.

#define _GNU_SOURCE
#include <stdint.h>
#include <string.h>
#include <malloc.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <fcntl.h>

enum {
  MAX_ARGS_COUNT = 256,
  MAX_CHAIN_LINKS_COUNT = 256
};

pid_t pid_arr[MAX_CHAIN_LINKS_COUNT];

typedef struct {
  char *command;
  uint64_t argc;
  char *argv[MAX_ARGS_COUNT];
} chain_link_t;

typedef struct {
  uint64_t chain_links_count;
  chain_link_t chain_links[MAX_CHAIN_LINKS_COUNT];
} chain_t;

void parse_commands(char *command, chain_link_t *link) {
  char *tmp = command;
  char *tmp2 = command;
  link->argc = 1;
  while ((tmp = strchr(tmp, ' '))) {
    link->argv[link->argc - 1] = strndup(tmp2, tmp - tmp2);
    link->argc++;
    tmp2 = ++tmp;
  }
  if (strlen(tmp2) > 0) {
    link->argv[link->argc - 1] = strdup(tmp2);
  }
  link->command = link->argv[0];
}

void create_chain(char *command, chain_t *chain) {
  char *tmp = command;
  char *tmp2 = command;
  chain->chain_links_count = 0;
  while ((tmp = strchr(tmp, '|'))) {
    if (tmp[0] == ' ') {
      ++tmp;
    }
    parse_commands(strndup(tmp2, tmp - tmp2 - 1), &(chain->chain_links[chain->chain_links_count]));
    tmp = tmp2 = tmp + 2;
    ++chain->chain_links_count;
  }
  if (strlen(tmp2) > 0) {
    if (tmp2[0] == ' ') {
      ++tmp2;
    }
    parse_commands(strdup(tmp2), &(chain->chain_links[chain->chain_links_count]));
    ++chain->chain_links_count;
  }
}

void run_chain(chain_t *chain) {
  size_t size = chain->chain_links_count - 1;
  if (chain->chain_links_count == 0) {
    fprintf(stderr, "No commands provided.\n");
    return;
  }
  int pipes[chain->chain_links_count][2];

  for (int i = 0; i < chain->chain_links_count - 1; ++i) {
    if (pipe(pipes[i]) == -1) {
      perror("pipe");
      exit(EXIT_FAILURE);
    }
  }

  for (int i = 0; i < chain->chain_links_count; ++i) {
    pid_t pid = fork();
    if (pid == -1) {
      perror("fork");
      exit(EXIT_FAILURE);
    } else if (pid == 0) {  // Child process
      if (i > 0) {
        dup2(pipes[i - 1][0], STDIN_FILENO);
        close(pipes[i - 1][0]);
        close(pipes[i - 1][1]);
      }
      if (i < chain->chain_links_count - 1) {
        dup2(pipes[i][1], STDOUT_FILENO);
        close(pipes[i][0]);
        close(pipes[i][1]);
      }
      execvp(chain->chain_links[i].command, chain->chain_links[i].argv);
      perror("execvp");
      exit(EXIT_FAILURE);
    }
  }
  for (int i = 0; i < chain->chain_links_count - 1; ++i) {
    close(pipes[i][0]);
    close(pipes[i][1]);
  }
  for (int i = 0; i < chain->chain_links_count; ++i) {
    wait(NULL);
  }
}

int main(int argc, char *argv[]) {
  chain_t chain;
  create_chain(argv[1], &chain);
  run_chain(&chain);
  return 0;
}

也就是说,测试类型为"pwd""ls""ls -l""ls -la""ls -la | wc -c""pwd | cut -d/ -f2""ls -la | wc | echo "1" | echo "1" | echo "1" | echo "1" | echo "1" | echo "1" | echo "1"",它工作成功,但在测试"ls -la | wc | wc -c"中,它挂起在最后一个进程上. 我假设最后一个wc的输入为空,这就是它挂起的原因. 这可能是什么问题?

推荐答案

我看到的问题是,在执行死刑之前,管道的每一端都被关闭.该代码可以很好地用于单个管道,因为它可以从Standart io FD进行写入和读取.正如你在这张[图表][1]中看到的,一些末端应该保持开放以供阅读.

    (...)
    else if (!pid)
    {
        close(pipes[i - 1][1]);
        close(pipes[i][0]);
        dup2(pipes[i][1], STDOUT_FILENO);
        //exec
    }
    else
    {
        //revert the upper one
    }

而且我也不确定是否能一下子创建所有的管道.可能需要关闭除需要的两个末端之外的所有其他管道末端,因为它们都是开放的. [1]:https://i.stack.imgur.com/u17DR.png

C++相关问答推荐

如果实际的syscall是CLONE(),那么为什么strace接受fork()呢?

为什么写入系统调用打印的字符数不正确?

来自stdarg.h的c中的va_args无法正常工作<>

如何判断宏参数是否为C语言中的整型文字

增加getaddrinfo返回的IP地址数量

在编译时参数化类型定义

如何创建一个C程序来存储5种动物的名字,并在用户 Select 其中任何一种动物时打印内存地址?

GCC不顾-fno-Builtin-SINCOS旗帜向SINCOS发出呼唤

#定义SSL_CONNECTION_NO_CONST

为什么用非常数指针变量改变常量静态变量时会出现分段错误?

获取前2个连续1比特的索引的有效方法

';\n&39;和';\r&39;中的';\n&39;之间有什么关系?

链表删除 node 错误

Fprintf正在写入多个 struct 成员,并且数据过剩

程序对大输入给出错误答案

macos/arm64 上地址空间不使用第一位吗?

可以从指针数组中的值初始化指针吗?

在 C/C++ 中原子按位与字节的最佳方法?

C 中类型说明符的顺序重要吗?

将帧从相机 (/dev/video0) 复制到帧缓冲区 (/dev/fb0) 会产生意外结果