0

我需要写我的管道流。我的程序应该获取另一个程序的名称并调用它们,第一个程序应该从第一个输出的 stdin 第二个读取,依此类推。最后一个程序在标准输出中打印结果。问题是它不起作用。当我将此程序调用到另外两个简单程序时(它们都是读取 x 并在它可以读取时打印 2*x),并给它一些数据,我想我应该立即得到结果,但我没有。更重要的是,当我给它文件结束时它没有反应。不要关注 safe_* 函数,它们与标准相同,但检查错误。请帮帮我=)

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "error.h"
#include "safe_functions.h"

void call(const char *filename, int in_descr, int out_descr, pid_t *sons, int n)
{
    sons[n] = safe_fork();
    if(sons[n] == 0)
    {
        safe_dup2(in_descr, STDIN_FILENO);
        safe_dup2(out_descr, STDOUT_FILENO);

        safe_execv(filename, (char **)NULL);
    }
}

int find_num(pid_t * sons, int n, pid_t id)
{
    for(int i=0; i<n; i++)
        if(sons[i] == id)
            return i;

    return -1;
}

int main(int argc, const char ** argv)
{

    int **descr;
    descr = (int**)safe_malloc(argc*sizeof(int*));
    for(int i=0; i<argc; i++)
        descr[i] = (int*) safe_malloc(2*sizeof(int));

    for(int i=1; i+1<argc; i++)
        safe_pipe(descr[i]);

    descr[0][0] = 0;
    descr[argc-1][1] = 1;

    pid_t *sons = safe_malloc((argc-1) * sizeof(pid_t));

    for(int i=1; i<argc; i++)
        call(argv[i], descr[i-1][0], descr[i][1], sons, i-1);

    int status;
    pid_t id;
    while(1)
    {
        id = safe_wait(&status);
        if(id == -1)
            break;

        if(WIFEXITED(status))
        {
            int num = find_num(sons, argc-1, id);
            safe_close(descr[num][0]);
            safe_close(descr[num+1][1]);
            continue;
        }

        if(WIFSIGNALED(status))
        {
            int num = find_num(sons, argc-1, id);
            fatal_error("Process was teminated by a signal", argv[num+1], WEXITSTATUS(status));
        }
    }

    free(sons);
    for(int i=0; i<argc; i++)
        free(descr[i]);
    free(descr);
}
4

1 回答 1

1

你没有足够的电话来close()!父级必须关闭其所有的管道副本。在将相关的管道描述符复制到标准输入和输出之后,孩子们也必须关闭每个管道描述符。否则,进程永远不会得到 EOF,因为有一个进程可以写入管道。

SSCCE(简短、独立、正确的示例

此代码使用我的stderr.hstderr.c代码代替您的error.h(如果您需要代码,请与我联系 - 请参阅我的个人资料)。它写出了safe_*函数——或者,至少,我对它们的实现。

dump_fds()函数报告在 0-19 范围内打开了哪些文件描述符,这对于这个程序和大多数程序来说已经足够了;一个更复杂的版本sysconf()用于确定要检查的文件描述符的数量,但该数量通常比使用中的数量大得多(例如 256 或更大)。我用它作为一种简单的方法来检查所有应该关闭的文件描述符是否已关闭。

有相当多的调试输出。调用execv()提供了正确的参数列表。

#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>

//#include "error.h"
//#include "safe_functions.h"

#include "stderr.h"

extern pid_t safe_fork(void);
extern void  safe_dup2(int old_fd, int new_fd);
extern void  safe_execv(const char *prog, char **argv);
extern void  safe_pipe(int *pipe_fds);
extern void *safe_malloc(size_t size);
extern int   safe_wait(int *status);
extern void  safe_close(int fd);

/* Report on open file descriptors (0..19) in process */
static void dump_fds(void)
{
    struct stat b;
    char buffer[32];
    sprintf(buffer, "%d: ", getpid());
    char *str = buffer + strlen(buffer);
    for (int i = 0; i < 20; i++)
        *str++ = (fstat(i, &b) == 0) ? 'o' : '-';
    *str++ = '\n';
    *str = '\0';
    fputs(buffer, stderr);
}

static void close_pipes(int **descr, int argc)
{
    for (int i = 0; i < argc; i++)
    {
        for (int j = 0; j < 2; j++)
        {
            if (descr[i][j] > 1)
            {
                err_remark("close %d\n", descr[i][j]);
                safe_close(descr[i][j]);
            }
        }
    }
}

static void call(char *filename, int in_descr, int out_descr, pid_t *sons, int n, int **descr, int argc)
{
    sons[n] = safe_fork();
    if (sons[n] == 0)
    {
        err_remark("call: %s\n", filename);
        char *argv[2] = { filename, NULL };
        err_remark("dup2(%d, %d)\n", in_descr, STDIN_FILENO);
        err_remark("dup2(%d, %d)\n", out_descr, STDOUT_FILENO);
        safe_dup2(in_descr, STDIN_FILENO);
        safe_dup2(out_descr, STDOUT_FILENO);
        close_pipes(descr, argc);
        dump_fds();
        safe_execv(argv[0], argv);
    }
}

static int find_num(pid_t *sons, int n, pid_t id)
{
    for (int i=0; i<n; i++)
    {
        if (sons[i] == id)
            return i;
    }
    return -1;
}

int main(int argc, char **argv)
{
    err_setarg0(argv[0]);
    err_setlogopts(ERR_PID);
    dump_fds();

    int **descr;
    descr = (int**)safe_malloc(argc*sizeof(int*));

    for (int i=0; i<argc; i++)
        descr[i] = (int*) safe_malloc(2*sizeof(int));

    for (int i=1; i+1<argc; i++)
        safe_pipe(descr[i]);

    descr[0][0] = 0;
    descr[argc-1][1] = 1;

    pid_t *sons = safe_malloc((argc-1) * sizeof(pid_t));

    for (int i=1; i<argc; i++)
    {
        err_remark("Command: %s\n", argv[i]);
        call(argv[i], descr[i-1][0], descr[i][1], sons, i-1, descr, argc);
    }

    close_pipes(descr, argc);

    while (1)
    {
        int status;
        pid_t id = safe_wait(&status);
        err_remark("wait: pid %d, status 0x%.4X\n", (int)id, status);

        if (id == -1)
            break;

        if (WIFEXITED(status))
        {
            int num = find_num(sons, argc-1, id);
            //safe_close(descr[num][0]);
            //safe_close(descr[num+1][1]);
            continue;
        }

        if (WIFSIGNALED(status))
        {
            int num = find_num(sons, argc-1, id);
            err_remark("Process %s was terminated by signal %d", argv[num+1], WEXITSTATUS(status));
        }
    }

    free(sons);
    for (int i=0; i<argc; i++)
        free(descr[i]);
    free(descr);

    return(0);
}


extern pid_t safe_fork(void)
{
    pid_t pid = fork();
    if (pid < 0)
        err_syserr("Failed to fork() ");
    return pid;
}

extern void safe_dup2(int old_fd, int new_fd)
{
    if (dup2(old_fd, new_fd) < 0)
        err_syserr("Failed to dup2(%d, %d) ", old_fd, new_fd);
}

extern void safe_execv(const char *prog, char **argv)
{
    execv(prog, argv);
    err_syserr("Failed to execv(\"%s\") ", prog);
}

extern void safe_pipe(int *pipe_fds)
{
    assert(pipe_fds != 0);
    if (pipe(pipe_fds) != 0)
        err_syserr("Failed to pipe() ");
    err_remark("pipe: %d, %d\n", pipe_fds[0], pipe_fds[1]);
}

extern void *safe_malloc(size_t size)
{
    void *vp = malloc(size);
    if (vp == 0)
        err_syserr("Out of memory ");
    return vp;
}

extern int safe_wait(int *status)
{
    assert(status != 0);
    return wait(status);
}

extern void safe_close(int fd)
{
    if (close(fd) < 0)
        err_syserr("Failed to close(%d)\n", fd);
}

示例输出

$ ./pipes-15845060 /bin/ps /usr/bin/sort /bin/cat
12096: ooo-----------------
pipes-15845060: pid=12096: pipe: 3, 4
pipes-15845060: pid=12096: pipe: 5, 6
pipes-15845060: pid=12096: Command: /bin/ps
pipes-15845060: pid=12096: Command: /usr/bin/sort
pipes-15845060: pid=12096: Command: /bin/cat
pipes-15845060: pid=12096: close 3
pipes-15845060: pipes-15845060: pid=12098: pid=12096: close 4
pipes-15845060: pid=12096: close 5
pipes-15845060: pid=12096: close 6
call: /bin/ps
pipes-15845060: pid=12098: dup2(0, 0)
pipes-15845060: pid=12098: dup2(4, 1)
pipes-15845060: pid=12099: call: /usr/bin/sort
pipes-15845060: pid=12099: dup2(3, 0)
pipes-15845060: pid=12099: dup2(6, 1)
pipes-15845060: pid=12098: pipes-15845060: pid=12099: close 3
pipes-15845060: pid=12099: close 4
pipes-15845060: pid=12099: close 5
pipes-15845060: pid=12099: close 6
12099: ooo-----------------
close 3
pipes-15845060: pid=12098: close 4
pipes-15845060: pid=12098: close 5
pipes-15845060: pid=12098: close 6
12098: ooo-----------------
pipes-15845060: pid=12100: call: /bin/cat
pipes-15845060: pid=12100: dup2(5, 0)
pipes-15845060: pid=12100: dup2(1, 1)
pipes-15845060: pid=12100: close 3
pipes-15845060: pid=12100: close 4
pipes-15845060: pid=12100: close 5
pipes-15845060: pid=12100: close 6
12100: ooo-----------------
pipes-15845060: pid=12096: wait: pid 12098, status 0x0000
  563 ttys000    0:00.03 -sh
  568 ttys001    0:00.03 -sh
  578 ttys003    0:00.03 -sh
  587 ttys002    0:00.03 -sh
  588 ttys005    0:00.15 -sh
  589 ttys004    0:00.20 -sh
  PID TTY           TIME CMD
12096 ttys004    0:00.00 ./pipes-15845060 /bin/ps /usr/bin/sort /bin/cat
12097 ttys004    0:00.00 sed /./s/^/    /
12099 ttys004    0:00.00 /usr/bin/sort
12100 ttys004    0:00.00 /bin/cat
pipes-15845060: pid=12096: wait: pid 12100, status 0x0000
pipes-15845060: pid=12096: wait: pid 12099, status 0x0000
pipes-15845060: pid=12096: wait: pid -1, status 0x0000
$
于 2013-04-06T19:05:27.867 回答