我有一个练习,我应该读取一个infile文本并用Unix管道(fork()等)传递它们并将它们打印到屏幕上以供初学者使用。我已经完成了但是现在我需要对来自在管道内输入(exec sort),然后打印出来。
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
int main(void)
{
FILE *readchar = fopen("text1", "r");
char ch;
int fd[2];
int i = 0;
char readbuffer[1024];
int ret = pipe(fd);
if (ret == -1)
{
perror("pipe");
exit(-1);
}
if (fork() == 0)
{
printf("childprocess\n");
while(1)
{
ch = fgetc(readchar);
if(ch==EOF){
break;
}
write(fd[1],&ch,1);
dup2(1,fd[1]);
execlp("sort", "sort", (char*) NULL); //this is crashing
printf("%c",ch);
}
printf("\n");
exit(0);
printf("end of childprocess\n");
}else
{
wait(0);
printf("%d: parentprocess\n", (int)getpid());
read(fd[0],readbuffer,sizeof(readbuffer));
printf("that was in the pipe : \n");
printf ("%s",readbuffer);
printf("\n");
}
return 0;
}
我可以在while(1)循环中使用execlp排序吗?我的意思是每当一个角色进入管道时,exec就会对管道进行分类。 或者我可以在while(1)语句之后(在管道中添加所有字符之后)对整个管道进行排序?当execlp排序开始时,代码现在只在第一个循环中崩溃。
infile数据:
abcdefg
123456
XXXXXX
01010101
答案 0 :(得分:2)
你拨打pipe()
两次;删除第一个。你打电话给fork()
两次;它不清楚你要删除哪一个。但是,删除第一个意味着最少的其他更改。您还需要避免关闭父级中的fd[1]
,以便第二个和后续子级仍具有要使用的有效管道。
当输出直接发送到终端(而不是通过管道)时,此代码至少有效:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
int main(void)
{
FILE *readchar = fopen("infile", "r");
char buf[1024];
int fd[2];
int i = 0;
int ret = pipe(fd);
if (ret == -1)
{
perror("pipe");
exit(-1);
}
while (fgets(buf, sizeof(buf), readchar) != NULL)
{
if (fork() == 0)
{
printf("child proceess\n");
close(fd[0]);
write(fd[1], buf, sizeof(buf));
exit(0);
}
else
{
wait(0);
printf("parent proceess");
//close(fd[1]);
read(fd[0], buf, 1024);
printf("buf: %s\n", buf);
printf("%d\n", ++i);
}
}
return 0;
}
如果将源副本复制到infile
,则会产生正确的输出行数(双倍行距)。
代码仍然不是很好,原因很多,其中最重要的是每行一个进程&#39;有点浪费,并且用缓冲区中的行内容分叉进程,然后将该缓冲区写回到父进程(已经知道缓冲区中的内容)是有点无意义的#39;。 OTOH,它确实使用管道在两个进程之间进行通信。
当我运行数据文件中显示的代码时:
abcdefg
123456
XXXXXX
01010101
我得到的输出是:
child proceess
parent proceessbuf: abcdefg
1
child proceess
parent proceessbuf: abcdefg
1
parent proceessbuf: 123456
2
child proceess
parent proceessbuf: abcdefg
1
parent proceessbuf: 123456
2
parent proceessbuf: XXXXXX
3
child proceess
parent proceessbuf: abcdefg
1
parent proceessbuf: 123456
2
parent proceessbuf: XXXXXX
3
parent proceessbuf: 01010101
4
嗯......这有点奇怪:第一个;那么1,2;那么1,2,3;然后是1,2,3,4。(在我的试验中,我没有发现这一点,最后的43行蜿蜒过去了两倍。)让我调查一下。但是没有无限循环,因此您将我的代码中的错误内容合并到您的内容中。
我为程序使用了名称xc19
(来源xc19.c
)。
上面代码的问题是我使用xc19 | pbcopy
来运行并将输出复制到剪贴板(在Mac上)。这意味着输出不再是行缓冲,而是完全缓冲的#39;因此,中间输出仍然在每个子节点的标准I / O缓冲区中,因此当子进程退出时,该信息被刷新。但每个孩子都在缓冲区中获得了更多信息。
修复非常简单:在父代码中使用fflush(0);
或fflush(stdout);
。这是一个具有更多压缩输出的版本(以及打印的PID形式的诊断):
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
int main(void)
{
FILE *readchar = fopen("infile", "r");
char buf[1024];
int fd[2];
int i = 0;
int ret = pipe(fd);
if (ret == -1)
{
perror("pipe");
exit(-1);
}
while (fgets(buf, sizeof(buf), readchar) != NULL)
{
if (fork() == 0)
{
printf("%d: child proceess\n", (int)getpid());
close(fd[0]);
write(fd[1], buf, sizeof(buf));
exit(0);
}
else
{
wait(0);
printf("%d: parent proceess\n", (int)getpid());
read(fd[0], buf, 1024);
printf("%d buf: %s", ++i, buf);
fflush(0);
}
}
return 0;
}
输出:
58878: child proceess
58876: parent proceess
1 buf: abcdefg
58879: child proceess
58876: parent proceess
2 buf: 123456
58880: child proceess
58876: parent proceess
3 buf: XXXXXX
58881: child proceess
58876: parent proceess
4 buf: 01010101