Pipestream和子进程 [英] Pipestream and child processes

查看:87
本文介绍了Pipestream和子进程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要写我的pipestream。我的程序应该得到另一个程序的名称和给他们打电话,第一个节目应该等从第一个输出标准输入秒读。最后程序打印出结果在标准输出。问题是,这是行不通的。当我把这个计划,另两个简单的程序(它们都是读取x和打印2 * X,同时它可以读取),并给它一些数据,我想,我应该立即得到结果,但我不知道。更重要的是,当我给它的文件结束它不反应。注意不要在safe_ *功能,它们是相同的非标准,但对于错误检查。救救我,请=)

 的#include<&unistd.h中GT;
#包括LT&; SYS / types.h中>
#包括LT&; SYS / wait.h>
#包括LT&;&errno.h中GT;
#包括LT&;&string.h中GT;
#包括LT&;&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括error.h
#包括safe_functions.h无效电话(为const char *文件名,INT in_descr,诠释out_descr,将为pid_t *儿子,INT N)
{
    儿子[N] = safe_fork();
    如果(儿子[N] == 0)
    {
        safe_dup2(in_descr,STDIN_FILENO);
        safe_dup2(out_descr,STDOUT_FILENO);        safe_execv(文件名,(字符**)NULL);
    }
}INT find_num(将为pid_t *儿子,整数N,将为pid_t ID)
{
    的for(int i = 0; I< N;我++)
        如果(儿子[I] == ID)
            返回我;    返回-1;
}INT主(INT ARGC,为const char ** argv的)
{    INT ** DESCR;
    DESCR =(INT **)的safe_malloc(ARGC * sizeof的为(int *));
    的for(int i = 0; I< ARGC,我++)
        DESCR [I] =(INT *)的safe_malloc(2 * sizeof的(INT));    的for(int i = 1; i + 1的< ARGC,我++)
        safe_pipe(DESCR [I]);    DESCR [0] [0] = 0;
    DESCR [的argc-1] [1] = 1;    将为pid_t *儿子=的safe_malloc((ARGC-1)* sizeof的(将为pid_t));    的for(int i = 1; I< ARGC,我++)
        调用(的argv [I],DESCR [I-1] [0],DESCR [I] [1],儿子,我-1);    INT状态;
    将为pid_t ID;
    而(1)
    {
        ID = safe_wait(安培;状态);
        如果(ID == -1)
            打破;        如果(WIFEXITED(状态))
        {
            INT NUM = find_num(儿子,ARGC-1,ID);
            safe_close(DESCR [NUM] [0]);
            safe_close(DESCR [NUM + 1] [1]);
            继续;
        }        如果(WIFSIGNALED(状态))
        {
            INT NUM = find_num(儿子,ARGC-1,ID);
            是fatal_error(,的argv [NUM + 1]进程被一个信号teminated,WEXITSTATUS(状态));
        }
    }    免费的(儿子);
    的for(int i = 0; I< ARGC,我++)
        免费(DESCR [I]);
    免费(DESCR);
}


解决方案

  

您有隔靴搔痒调用的close()!家长必须关闭管道的所有副本。复制相关管道描述符标准输入和输出后,孩子们必须关闭所有的管道描述过。否则,过程永远不会EOF,因为有可能写入该管道的过程。


的SSCCE(短的,独立的,正确的示例

这code使用我的 stderr.h stderr.c code代替你的 error.h (如果你想在code联系我 - 看我的配置文件)。它写出了安全_ * 功能 - 或者,至少,我执行起来

dump_fds()函数报告上文件描述符的范围是0-19,这足以满足这一点,大多数程序打开;一个更复杂的版本可以与的sysconf()来确定文件描述符来检查的数量,但是数量通常大得多(例如256或大于)在使用数。我用它作为一个简单的方法来检查所有的文件描述符应该关闭被关闭。

有相当大的调试输出。要将呼叫 execv()提供一个适当的参数列表。

 的#include<&ASSERT.H GT;
#包括LT&;&errno.h中GT;
#包括LT&;&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&string.h中GT;
#包括LT&; SYS / stat.h>
#包括LT&; SYS / wait.h>
#包括LT&;&unistd.h中GT;//#包括error.h
//#包括safe_functions.h#包括stderr.hEXTERN将为pid_t safe_fork(无效);
EXTERN无效safe_dup2(INT old_fd,诠释new_fd);
EXTERN无效safe_execv(为const char * PROG,焦炭** argv的);
EXTERN无效safe_pipe为(int * pipe_fds);
EXTERN无效*的safe_malloc(为size_t大小);
EXTERN INT safe_wait(INT *状态);
EXTERN无效safe_close(INT FD);/ *在进程打开文件的描述符(0..19)报告* /
静态无效dump_fds(无效)
{
    struct stat中B:
    字符缓冲区[32];
    的sprintf(缓冲器,%D:,GETPID());
    字符*海峡=缓冲+ strlen的(缓冲);
    的for(int i = 0; I< 20;我++)
        * STR + =(FSTAT(I,和b)== 0)? 'O':' - ';
    * STR + ='\\ n';
    *海峡='\\ 0';
    的fputs(缓冲,标准错误);
}静态无效close_pipes(INT ** DESCR,INT ARGC)
{
    的for(int i = 0; I< ARGC,我++)
    {
        为(中间体J = 0; J&2; J ++)
        {
            如果(DESCR [I] [j]的大于1)
            {
                err_remark(亲密%d个\\ N,DESCR [I] [J]);
                safe_close(DESCR [I] [J]);
            }
        }
    }
}静态无效调用(字符*文件名,INT in_descr,诠释out_descr,将为pid_t *儿子,INT N,INT ** DESCR,INT ARGC)
{
    儿子[N] = safe_fork();
    如果(儿子[N] == 0)
    {
        err_remark(来电:%S \\ n,文件名);
        的char * argv的[2] = {文件名,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的);
    }
}静态INT find_num(将为pid_t *儿子,INT N,将为pid_t ID)
{
    的for(int i = 0; I< N;我++)
    {
        如果(儿子[I] == ID)
            返回我;
    }
    返回-1;
}INT主(INT ARGC,字符** 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,我++)
        DESCR [I] =(INT *)的safe_malloc(2 * sizeof的(INT));    的for(int i = 1; i + 1的< ARGC,我++)
        safe_pipe(DESCR [I]);    DESCR [0] [0] = 0;
    DESCR [的argc-1] [1] = 1;    将为pid_t *儿子=的safe_malloc((ARGC-1)* sizeof的(将为pid_t));    的for(int i = 1; I< ARGC,我++)
    {
        err_remark(命令:%S \\ N的argv [I]);
        调用(的argv [I],DESCR [I-1] [0],DESCR [I] [1],儿子,I-1,DESCR,ARGC);
    }    close_pipes(DESCR,ARGC);    而(1)
    {
        INT状态;
        将为pid_t ID = safe_wait(安培;状态);
        err_remark(等待:PID%D,状态为0x%.4X \\ n,(INT)ID,状态);        如果(ID == -1)
            打破;        如果(WIFEXITED(状态))
        {
            INT NUM = find_num(儿子,ARGC-1,ID);
            // safe_close(DESCR [NUM] [0]);
            // safe_close(DESCR [NUM + 1] [1]);
            继续;
        }        如果(WIFSIGNALED(状态))
        {
            INT NUM = find_num(儿子,ARGC-1,ID);
            err_remark(,的argv [NUM + 1]进程%S被信号%d个终止,WEXITSTATUS(状态));
        }
    }    免费的(儿子);
    的for(int i = 0; I< ARGC,我++)
        免费(DESCR [I]);
    免费(DESCR);    返回(0);
}
EXTERN将为pid_t safe_fork(无效)
{
    将为pid_t PID =叉();
    如果(PID℃,)
        err_syserr(无法fork()的);
    返回PID;
}EXTERN无效safe_dup2(INT old_fd,诠释new_fd)
{
    如果(dup2(old_fd,new_fd)℃的)
        err_syserr(无法dup2(%D,%D),old_fd,new_fd);
}EXTERN无效safe_execv(为const char * PROG,焦炭** argv的)
{
    execv(PROG,argv的);
    err_syserr(无法execv(\\%s \\的),PROG);
}EXTERN无效safe_pipe为(int * pipe_fds)
{
    断言(pipe_fds!= 0);
    如果(管道(pipe_fds)!= 0)
        err_syserr(无法管());
    err_remark(管数:%d,%d个\\ N,pipe_fds [0],pipe_fds [1]);
}EXTERN无效*的safe_malloc(为size_t大小)
{
    无效* VP =的malloc(大小);
    如果(VP == 0)
        err_syserr(内存不足);
    返回VP;
}EXTERN INT safe_wait(INT *状态)
{
    断言(状态!= 0);
    返回等待(状态);
}EXTERN无效safe_close(INT FD)
{
    如果(接近(FD)℃,)
        err_syserr(无法关闭(%D)\\ n,FD);
}

示例输出

  $ ./pipes-15845060 /斌/ PS的/ usr / bin中/排序/斌/猫
12096:OOO -----------------
管道-15845060:PID = 12096:管:3,4
管道-15845060:PID = 12096:管:5,6
管道-15845060:PID = 12096:命令:/ bin中/ PS
管道-15845060:PID = 12096:命令:/ usr / bin中/排序
管道-15845060:PID = 12096:命令:/ bin中/猫
管道-15845060:PID = 12096:关闭3
管道-15845060:管-15845060:PID = 12098:PID = 12096:关闭4
管道-15845060:PID = 12096:关闭5
管道-15845060:PID = 12096:关闭6
拨打:/ bin中/ PS
管-15845060:PID = 12098:dup2(0,0)
管-15845060:PID = 12098:dup2(4,1)
管道-15845060:PID = 12099:调用:在/ usr / bin中/排序
管-15845060:PID = 12099:dup2(3,0)
管-15845060:PID = 12099:dup2(6,1)
管道-15845060:PID = 12098:管道-15845060:PID = 12099:关闭3
管道-15845060:PID = 12099:关闭4
管道-15845060:PID = 12099:关闭5
管道-15845060:PID = 12099:关闭6
12099:OOO -----------------
接近3
管道-15845060:PID = 12098:关闭4
管道-15845060:PID = 12098:关闭5
管道-15845060:PID = 12098:关闭6
12098:OOO -----------------
管道-15845060:PID = 12100:拨打:/ bin中/猫
管-15845060:PID = 12100:dup2(5,0)
管-15845060:PID = 12100:dup2(1,1)
管道-15845060:PID = 12100:关闭3
管道-15845060:PID = 12100:关闭4
管道-15845060:PID = 12100:关闭5
管道-15845060:PID = 12100:关闭6
12100:OOO -----------------
管道-15845060:PID = 12096:等待:PID 12098,状态为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 /斌/ PS的/ usr / bin中/排序/斌/猫
12097 ttys004 0:00.00 SED /./s/^/ /
12099 ttys004 0:00.00的/ usr / bin中/排序
12100 ttys004 0:00.00 /斌/猫
管道-15845060:PID = 12096:等待:PID 12100,状态为0x0000
管道-15845060:PID = 12096:等待:PID 12099,状态为0x0000
管道-15845060:PID = 12096:等待:PID -1,状态为0x0000
$

I need to write my pipestream. My program should get names of another programs and call them, first program should read from stdin second from output of the first an so on. Last program print the result in stdout. The problem is it doesn't work. When I call this program to two another simple programs (they both are to read x and print 2*x while it can read), and give it some data I suppose that I should get result immediately, but I don't. What is more when I give it end of file it doesn't react. Don't pay attention on safe_* functions, they are the same as standart, but the check for an errors. Help me, please =)

#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);
}

解决方案

You have nowhere near enough calls to close()! The parent must close all its copies of the pipes. After duplicating the relevant pipe descriptors to standard input and output, the children must close every pipe descriptor too. Otherwise, the processes never get EOF because there's a process that could write to the pipes.

An SSCCE (Short, Self-Contained, Correct Example)

This code uses my stderr.h and stderr.c code in place of your error.h (contact me if you want the code — see my profile). It writes out the safe_* functions — or, at least, my implementation of them.

The dump_fds() function reports on which file descriptors are open in the range 0-19, which is sufficient for this and most programs; a more complex version works with sysconf() to determine the number of file descriptors to check, but the number is usually vastly greater (eg 256 or larger) than the number in use. I use it as a simple way to check that all the file descriptors that should be closed are closed.

There is considerable debug output. The call to execv() provides a proper argument list.

#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);
}

Example Output

$ ./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
$

这篇关于Pipestream和子进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆