【问题标题】:Simple multiple child exec'd fork segfaulting when trying to read from stdout of child尝试从子级的标准输出读取时,简单的多个子级执行分叉段错误
【发布时间】:2014-10-01 02:41:58
【问题描述】:

我设置了一个简单的 fork 示例来 fork 和 exec 2 个子项,然后通过管道读取它们的输出,但是我有一个段错误(发生在 close(piping[i][1]);)并且无法找出原因。请参阅下面的代码:

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

int reader(int *piping[]) {
    char readstring[50];
    char readstring2[50];
    FILE *outPut;
    FILE *outPut2;
    outPut = fdopen(piping[0][0], "r");
    outPut2 = fdopen(piping[1][0], "r");
    fgets(readstring, sizeof(readstring), outPut);
    fgets(readstring2, sizeof(readstring2), outPut2);
    printf("%s\n", readstring);
    printf("%s\n", readstring2);
    return 0;
}

int main(void) {
    int i;
    int j;
    int pid;
    int **piping = malloc(sizeof(int*) *2);
    for(i = 0; i < 2; ++i) {
        piping[i] = malloc(sizeof(int) *2); 
    }   
    for(j = 0; j < 2; ++j) {
        pipe(piping[j]);
        if((pid = fork()) == -1)   
            fprintf(stderr, "error reading pipe\n");
            exit(1);
        } else if(pid == 0) {
            //child
            //close read pipes dup2 write pipes to stdout
            //then close old write pipes
            close(piping[j][0]);
            if(dup2(piping[j][1], 1) == -1) {
                fprintf(stderr, "error dup2");
                exit(2);
            }
            close(piping[j][0]);
            close(1);
            if(execlp("./playex", "playex", NULL)) {
                fprintf(stderr, "exec error\n");
            }
        } else {
            //parent
            close(piping[j][1]);
        }
    }
    reader(piping);
}

上面是管道和执行程序应该阅读的主要功能,下面是它运行的基本程序。

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

int main(void) {
    fprintf(stdout, "go\n");
}

我尝试修复段错误,但没有成功,请帮助定位和修复问题。

【问题讨论】:

  • 使用调试器。找出段错误在哪里。
  • 对不起,我忘了包括它关闭时的段错误(管道[i][1]),这是我无法弄清楚的。由于所有帐户,我需要关闭父级的写入端。
  • malloc() 用于使一个管道位于管道[0],一个管道位于管道[1],这就是我的文件所在的位置。(我使用它是因为我需要将其调整为更大通过参数进行缩放,以便我可以将它们划分为大小)。我不应该吗?
  • execlp() 唯一返回的时间是它失败的时候,所以你真的不需要测试它的返回值。但是,您应该在报告错误消息后退出。但是,这些都不会导致分段错误。
  • 为什么在execlp() 之前有close(1); - 这会小心地关闭您刚刚设置为写入管道的标准输出。那会带来一些麻烦。您没有检查fgets() 调用是否有效——或者fdopen() 调用是否有效——因此您不知道使用文件流或您(可能或不可能)已读取的缓冲区是否安全。 Yu 在打印 go 的最小程序中有 4 个不必要的标题。

标签: c segmentation-fault exec fork pipe


【解决方案1】:

您的主要问题是(在您编辑问题以隐藏它最初显示的内容之前)您在管道数组的范围之外编写:

for(i = 0; i < 2; ++i) {
    piping[i] = malloc(sizeof(int) *2); 
}   
for(j = 0; j < 2; ++j) {
    pipe(piping[i]);

您正在索引j 上的第二个循环,而不是i,因此您使用的是未分配的piping[2]。冲洗并重复。

您可以通过删除ij 的当前定义并使用:

for (int i = 0; i < 2; ++i) {
    piping[i] = malloc(sizeof(int) *2); 
}   
for (int j = 0; j < 2; ++j) {
    pipe(piping[i]);

现在i 将在第二个循环中未定义。

【讨论】:

  • 是的,非常感谢,我刚才注意到了,现在觉得自己像个白痴。
  • 欢迎来到俱乐部;有时我们都觉得自己像个白痴(但当你开始编程时,这种情况往往比你编程多年后发生的要多)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-18
  • 1970-01-01
  • 1970-01-01
  • 2019-10-17
  • 2017-03-28
相关资源
最近更新 更多