我希望有一个父母和2个孩子。
父文件从文件“a.txt”读取并将管道发送给第一个孩子;第一个孩子读取字符并向第二个孩子发送较低字母的字符。
第二个孩子在“b.txt”中打印每个不同的字符和出现次数(每行),然后通过管道向父母发送不同字符的数量。父节点打印第二个孩子的结果。
我已经完成了从父母到1个孩子的管道,并且测试我已经将管道放回到父管道。
我无法弄明白的是如何让管道进入第二个孩子。我一直在寻找有关dup2
的信息,但我不知道如何使其发挥作用。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
void main()
{
int pfd1[2], pfd2[2], pid1, pid2, pfin, status, fd;
char *c = (char *)malloc(sizeof(char));
if (pipe(pfd1) < 0) {
printf("Eroare la crearea pipe-ului\n");
exit(1);
}
if (pipe(pfd2) < 0) {
printf("Eroare la crearea pipe-ului\n");
exit(1);
}
if ((pid1 = fork()) < 0) {
printf("Eroare la fork\n");
exit(1);
}
if (pid1 == 0) { /*child */
close(pfd1[1]);
while (read(pfd1[0], c, 1) > 0) {
//printf("%s",c);
if (islower(*c)) {
close(pfd2[0]);
//inchid capul de citire; scriu in pipe
write(pfd2[1], c, 1);
////dup??????
}
}
printf("\n");
write(pfd[1], buff, len);
close(pfd1[0]);
close(pfd2[1]);
exit(0);
}
if ((pid2 = fork()) < 0) {
printf("Eroare la fork\n");
exit(1);
}
if (pid2 == 0) {
printf("second child");
exit(0);
}
/* parent */
close(pfd1[0]);
close(pfd2[1]);
fd = open("date.txt", O_RDONLY);
while (read(fd, c, 1) > 0) {
write(pfd1[1], c, 1);
}
close(pfd1[1]); /* la sfarsit inchide si capatul utilizat */
close(pfin);
while (read(pfd2[0], c, 1) > 0)
printf("%s", c);
close(pfd2[0]);
printf("%d", wait(&status));
printf("%d", wait(&status));
}
答案 0 :(得分:2)
我对您的代码有一些具体的评论:
char *c = (char *)malloc(sizeof(char));
虽然这没有任何问题,但也不需要从堆中分配此char
。更惯用的方法是在此使用char c;
,然后将&c
传递给read(2)
和write(2)
系统调用。 (更惯用的是使用C标准IO工具; freopen(3)
,getchar(3)
和putchar(3)
- 但在此代码完全按照您的要求运行之前不要进行转换它,因为它是你试图解决的问题的另一个复杂因素。)
if ((pid1 = fork()) < 0) {
printf("Eroare la fork\n");
exit(1);
}
通过使用您自己的错误消息,您错过了重要的错误信息。您应该使用perror(3)
来打印错误消息。这将为您和您的用户提供他们可以搜索的错误的实际原因。如果您的用户遇到fork(2)
setrlimit(2)
最大进程限制(系统范围的进程限制,超出内核内存),则NPROC
可能会失败。
if ((pid1 = fork()) < 0) {
perror("Eroare la fork");
exit(1);
}
您还应该检查open(2)
来电的返回值。 (你假设也检查来自write(2)
和close(2)
的返回值是否有错误,但处理这些错误更难。只需打印错误并退出就是一个好的开始对于大多数程序。)
while (read(pfd1[0], c, 1) > 0) {
//printf("%s",c);
if (islower(*c)) {
close(pfd2[0]);
这是close(2)
调用的错误位置 - 您不应该为每个输入字符反复关闭此文件描述符。如果您检查close(2)
返回值,您会注意到errno
设置为EBADF
,因为文件描述符在第二次和后续调用中不再有效。
现在,针对您来到这里的问题:fork()
,pipe()
和dup2()
调用的序列将挂接管道中的所有进程并将数据发送回父进程。由于pipe(2)
会创建单向pipe(7)
,因此您需要为父级和子级之间的两个方向调用pipe(2)
四次。如果将管道端点存储在具有对您有意义的名称的数组中,则可以更容易地跟踪它们。也许创建名为to_
的数组用于写入和from_
用于阅读:
int to_child[2];
int from_parent[2];
int to_parent[2];
int from_child[2];
for (int i=0; i<2; i++) {
int p[2];
if (pipe(p) == -1) {
perror("pipe");
exit(1);
}
/* from parent to child */
to_child[i] = p[1];
from_parent[i] = p[0];
if (pipe(p) == -1) {
perror("pipe");
exit(1);
}
/* from child to parent */
to_parent[i] = p[1];
from_child[i] = p[0];
}
请注意,除非您想执行其他程序来处理“过滤器”,否则您实际上 不需要使用dup2(2)
来重新排列文件描述符“任务。只需read(2)
使用from_parent[...]
或from_child[...]
描述符,write(2)
使用to_child[...]
和to_parent[...]
描述符。
使用socketpair(2)
AF_UNIX
创建双向套接字可能会让整个过程变得更容易,然后可以像以下相同的方式读取和写入任何其他BSD风格的插座。有关概述,请参阅socket(7)
和unix(7)
。
答案 1 :(得分:0)
您不需要dup()
。只需在父进程中打开管道,然后在每个进程中close()
打开您不需要的端点,只需使用您需要的端点。
请注意,这意味着父级将关闭管道的两个端点以进行子级通信。该管道的每个端点将由其中一个子节点使用。每个孩子也应该关闭它不使用的端点。
答案 2 :(得分:0)
感谢您的回答。 这是整个问题的代码。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
void main()
{
int pfd1[2],pfd2[2],pfd3[2],pid1,pid2,status,fd,fo;
char letter[32][2];
int letternumber=0,i,sw=0;
char* c = (char*)malloc(sizeof(char));
//pipe creation
if(pipe(pfd1)<0){
perror("Eroare la crearea pipe-ului");
exit(1);
}
if(pipe(pfd2)<0){
perror("Eroare la crearea pipe-ului\n");
exit(1);
}
if(pipe(pfd3)<0){
perror("Eroare la crearea pipe-ului\n");
exit(1);
}
//make first child
if((pid1=fork())<0){
perror("Eroare la fork\n");
exit(1);
}
if(pid1==0) //child process
{
if(close(pfd1[1])<0) {perror("Eroare close");exit(1);} // close write end; process will read from pipe
if(close(pfd2[0])<0) {perror("Eroare close");exit(1);} //close read end; write in pipe
while (read(pfd1[0], c, 1) > 0){
if(islower(*c)) write(pfd2[1],c,1);//writing in pipe
}
if(close(pfd1[0])<0) {perror("Eroare close");exit(1);} /* close other ends */
if(close(pfd2[1])<0) {perror("Eroare close");exit(1);}
if(close(pfd3[0])<0) {perror("Eroare close");exit(1);}
if(close(pfd3[1])<0) {perror("Eroare close");exit(1);}
exit(0);
}
//make second child
if((pid2=fork())<0){
perror("Eroare la fork");
exit(1);
}
if(pid2==0){ /* second child*/
if(close(pfd1[0])<0) {perror("Eroare close");exit(1);}
if(close(pfd1[1])<0) {perror("Eroare close");exit(1);}
if((fo=open("statistica.txt", O_CREAT | O_TRUNC | O_RDWR,
S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IROTH))==-1)
{perror("Eroare open");exit(1);}
if(close(pfd2[1])<0) {perror("Eroare close");exit(1);}
letter[0][0]='A';
letter[0][1]=0;
while(read(pfd2[0],c,1)>0) {
for(i=0;i<=letternumber;i++)
if(letter[i][0]==*c) {letter[i][1]++;sw=1;}
if (sw==0){
letter[letternumber][0]=*c;
letter[letternumber++][1]=1;
}
sw=0;
}
printf("\n");//why won't it write to file without it;
//wihtout it, it writes to screen?
if(close(pfd2[0])<0) {perror("Eroare close");exit(1);}
dup2(fo,1);
for(i=0;i<letternumber;i++)
printf("%c %d\n",letter[i][0],letter[i][1]);
if(close(fo)<0) {perror("Eroare close");exit(1);}
if(close(pfd3[0])<0) {perror("Eroare close");exit(1);} //close read end; going to write in pipe
dup2(pfd3[1],1);
printf("%d",letternumber);
if(close(pfd3[1])<0) {perror("Eroare close");exit(1);}
exit(0);
}
/* parent process */
if(close(pfd1[0])<0) {perror("Eroare close");exit(1);} // close read end; write in pipe
if(close(pfd2[0])<0) {perror("Eroare close");exit(1);}
if(close(pfd2[1])<0) {perror("Eroare close");exit(1);}
if(close(pfd3[1])<0) {perror("Eroare close");exit(1);}
if((fd=open("date.txt",O_RDONLY))==-1)
{perror("Eroare open");exit(1);}
while(read(fd,c,1)>0)
write(pfd1[1],c,1); //write in pipe
if(close(pfd1[1])<0) {perror("Eroare close");exit(1);}
//dup2(pfd3[0],0);
while(read(pfd3[0],c,1)>0) printf("%c",*c);
printf("\n");
if(close(pfd3[0])<0) {perror("Eroare close");exit(1);}
wait(&status);
wait(&status);
}