我需要编写我的管道流。我的程序应该获取另一个程序的名称并调用它们,第一个程序应该从第一个输出的stdin读取第二个等等。最后一个程序在stdout中打印结果。问题是它不起作用。当我把这个程序称为另外两个简单程序时(它们都是读取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);
}
答案 0 :(得分:1)
你没有足够的电话
close()
!父级必须关闭所有管道副本。在将相关管道描述符复制到标准输入和输出之后,子节点也必须关闭每个管道描述符。否则,进程永远不会获得EOF,因为有一个进程可以写入管道。
此代码使用我的stderr.h
和stderr.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
$