gpt4 book ai didi

c - 使用 Unix 管道读取 infile 并对其进行排序

转载 作者:太空宇宙 更新时间:2023-11-04 08:08:09 25 4
gpt4 key购买 nike

我有一个练习,我应该读取 infile 文本并使用 Unix 管道(fork() 等)传递它们,并将它们打印到屏幕上以供初学者使用。我已经完成了,但现在我需要对字符进行排序infile 在管道中(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

最佳答案

你调用了 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 后,它生成了正确数量的输出行(双倍行距)。

由于很多原因,代码仍然不好,其中最重要的是“每行一个进程”有点浪费,以及“用缓冲区中的行的内容派生一个进程,然后将该缓冲区写回 parent (已经知道缓冲区中有什么)有点毫无意义'。 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 上)。这意味着输出不再是行缓冲的,而是“完全缓冲的”。因此,中间输出仍在每个子进程的标准 I/O 缓冲区中,因此当子进程退出时,该信息被刷新。但是每个 child 都在缓冲区中获得了更多信息。

修复非常简单:在父代码中使用 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

关于c - 使用 Unix 管道读取 infile 并对其进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41235974/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com