我正在编写一个程序,在其中我进行了两次分叉以创建2个子进程,这些子进程通过其stdout将信息发送给父进程。孩子们启动该程序使其递归。发生的情况是,父级在读取子级时陷入了读取循环,但这不是永远的循环(存在有限且预期的输出)。它只是无法超越它。
char response1[256];
double complex r1[sizeof(workable)/sizeof(float)];
char* thing = NULL;
int countC1 = 1;
int bytesread;
char* response1Whole = NULL;
while((bytesread = read(pipefdc1b[0],response1, 256)) > 0){
fprintf(stderr,"PID:%d -> Reading Bytes from Child 1 Bytes read: %d\n\n", getpid(), bytesread);
if(bytesread == 256){
response1Whole = (char*) realloc(response1Whole, countC1*256 );
}else{
response1Whole = (char*) realloc(response1Whole, (countC1-1)*256+bytesread);
}
strcat(response1Whole, response1);
countC1++;
fprintf(stderr,"PID:%d -> Current Builts Input %s\n\n", getpid(), response1Whole);
}
fprintf(stderr,"PID:%d -> Child 1 Read\n\n", getpid());
这是我认为遇到问题的代码段。它打印出所有“当前构建的输入”和“从子级1读取字节”部分,但从不打印“子级1读取”部分。值得注意的是,这是一个有限的确定性输出,它读取的内容是预期的结果,该程序只是停止了。
if(count == 1){
fprintf(stdout,"%s", st);
fflush(stdout);
exit(EXIT_SUCCESS);
}
这是确定输出的代码块。我觉得这里可能会出现一些问题,即它没有正确终止输出流,但随后又退出了。
这是从创建管道到“问题”区域的代码:
int pipefdc1a[2]; //p->c1
int pipefdc1b[2]; //c1->p||
int pipefdc2a[2]; //p->c1
int pipefdc2b[2]; //c2->p
if(pipe(pipefdc1a) == -1){
fprintf(stderr, "Pipe Creation Failed\n");
exit(EXIT_FAILURE);
}
if(pipe(pipefdc1b) == -1){
fprintf(stderr, "Pipe Creation Failed\n");
exit(EXIT_FAILURE);
}
if(pipe(pipefdc2a) == -1){
fprintf(stderr, "Pipe Creation Failed\n");
exit(EXIT_FAILURE);
}
if(pipe(pipefdc2b) == -1){
fprintf(stderr, "Pipe Creation Failed\n");
exit(EXIT_FAILURE);
}
//fprintf(stderr,"PID:%d -> Pipes Created\n\n", getpid());
fflush(stdout);
pid_t pid = fork();
pid_t pid2;
switch (pid) {
case -1:
fprintf(stderr, "Cannot fork!\n");
exit(EXIT_FAILURE);
case 0:
//child 1
close(pipefdc1a[1]);
close(pipefdc1b[0]);
close(pipefdc2a[0]);
close(pipefdc2a[1]);
close(pipefdc2b[0]);
close(pipefdc2b[1]);
dup2(pipefdc1a[0],STDIN_FILENO);
close(pipefdc1a[0]);
dup2(pipefdc1b[1], STDOUT_FILENO);
close(pipefdc1b[1]);
execlp("./forkFFT","forkFFT", NULL);
exit(EXIT_FAILURE);
default:
//parent
fflush(stdout);
pid2 = fork();
switch(pid2){
case -1:
fprintf(stderr, "Cannot fork!\n");
exit(EXIT_FAILURE);
case 0:
//child 2
//fprintf(stderr,"PID:%d -> New Child 2 Created\n\n", getpid());
close(pipefdc1a[1]);
close(pipefdc1a[0]);
close(pipefdc1b[0]);
close(pipefdc1b[1]);
close(pipefdc2a[1]);
close(pipefdc2b[0]);
dup2(pipefdc2a[0],STDIN_FILENO);
close(pipefdc2a[0]);
dup2(pipefdc2b[1], STDOUT_FILENO);
close(pipefdc2b[1]);
execlp("./forkFFT","forkFFT", NULL);
exit(EXIT_FAILURE);
default:
//parent
fprintf(stderr, "entered parent switch. PID1: %d, PID2: %d\n\n", pid, pid2);
write(pipefdc1a[1], stp1, evensize);
write(pipefdc2a[1], stp2, oddsize);
close(pipefdc1a[1]);
close(pipefdc2a[1]);
char response1[256];
char response2[256];
double complex r1[sizeof(workable)/sizeof(float)];
double complex r2[sizeof(workable)/sizeof(float)];
char* thing = NULL;
int countC1 = 1;
int bytesread;
char* response1Whole = NULL;
while((bytesread = read(pipefdc1b[0],response1, 256)) > 0){
fprintf(stderr,"PID:%d -> Reading Bytes from Child 1 Bytes read: %d\n\n", getpid(), bytesread);
if(bytesread == 256){
response1Whole = (char*) realloc(response1Whole, countC1*256 );
}else{
response1Whole = (char*) realloc(response1Whole, (countC1-1)*256+bytesread);
}
strcat(response1Whole, response1);
countC1++;
fprintf(stderr,"PID:%d -> Current Builts Input %s\n\n", getpid(), response1Whole);
}
fprintf(stderr,"PID:%d -> Child 1 Read\n\n", getpid());
char* token = strtok(response1Whole, "\n");
while(token != NULL){
double real = (double)strtof(token, &thing);
if(token == thing){
fprintf(stderr, "Real Part is NAN\n");
exit(EXIT_FAILURE);
}
fprintf(stderr, "Real Number Read from child 1: %lf. PID1: %d, PID2: %d\n\n", real, pid, pid2);
double imaginary = 0.0;
if(thing != NULL){
fprintf(stderr,"Thing String: %s\n", thing);
char* check = NULL;
imaginary = (double)strtof(thing, &check);
if(check == thing){
fprintf(stderr, "Imaginary Part is NAN\n");
exit(EXIT_FAILURE);
}
}
fprintf(stderr, "Imaginary part of number 1: %lf. PID1: %d, PID2: %d\n\n",imaginary, pid, pid2);
r1[countC1] = real + imaginary*I;
token = strtok(NULL,"\n");
}
fprintf(stderr, "made it 1!\n\n");
char* thing2 = NULL;
int countC2 = 0;
FILE* pipe2File = fdopen(pipefdc2b[0], "r");
while(fgets(response2, 256, pipe2File) != NULL){
fprintf(stderr, "Reading from child 2. PID1: %d, PID2: %d\n\n", pid, pid2);
double real = (double)strtof(response2, &thing2);
if(response1 == thing2){
fprintf(stderr, "Real Part is NAN\n");
exit(EXIT_FAILURE);
}
fprintf(stderr, "Real Number Read from child 2: %lf. PID1: %d, PID2: %d\n\n", real, pid, pid2);
double imaginary = 0.0;
if(thing2 != NULL && thing2[0] != '\n'){
fprintf(stderr,"Thing2 String: %s\n", thing2);
char* check2 = NULL;
imaginary = (double)strtof(thing2, &check2);
if(check2 == thing2){
fprintf(stderr, "Imaginary Part is NAN\n");
exit(EXIT_FAILURE);
}
}
fprintf(stderr, "Imaginary part of number 2: %lf. PID1: %d, PID2: %d\n\n",imaginary, pid, pid2);
r2[countC2] = real + imaginary*I;
countC2++;
}
fclose(pipe2File);
fprintf(stderr, "made it 2!\n\n");
waitpid(pid, &status, 0);
if(status == 1){
fprintf(stderr, "Child did not terminate normally!\n");
exit(EXIT_FAILURE);
}
waitpid(pid2, &status, 0);
if(status == 1){
fprintf(stderr, "Child did not terminate normally!\n");
exit(EXIT_FAILURE);
}
我为孩子1和2尝试了2个不同的循环,因为在某个时候我发现这是问题所在,但不是。
我在某种程度上限制了对C的理解;如果您能回答并解释,那就太好了。
我正在尝试遵守“最低要求的代码”规则,但是如果您觉得需要其他条件,请询问,我将添加它们。
答案 0 :(得分:0)
正如我在comment中所猜到的那样,您关闭的文件描述符不足-这次的问题出在父级,尽管通常是子进程没有完成足够的关闭。
经验法则:如果您
dup2()
管道的一端到标准输入或标准输出,同时关闭两个
由返回的原始文件描述符
pipe()
尽快地。
特别是,在使用任何
exec*()
系列功能。
如果您将描述符与任何一个重复,则该规则也适用
dup()
要么
fcntl()
与F_DUPFD
您通过4个pipe()
调用创建了8个文件描述符。在孩子中,请根据经验法则将其关闭。
但是,在尝试从子级读取到EOF之前,您的父级仅关闭2个文件描述符。而且,由于它仍然具有从开放读取的管道的写端,因此它将永远不会得到EOF指示,因为从理论上讲它可以写入管道。
因此,您的父代码如下:
write(pipefdc1a[1], stp1, evensize);
write(pipefdc2a[1], stp2, oddsize);
close(pipefdc1a[1]);
close(pipefdc2a[1]);
应更像:
write(pipefdc1a[1], stp1, evensize);
write(pipefdc2a[1], stp2, oddsize);
close(pipefdc1a[1]);
close(pipefdc2a[1]);
close(pipefdc1a[0]); // Extra
close(pipefdc2a[0]); // Extra
close(pipefdc1b[1]); // Extra
close(pipefdc2b[1]); // Read all about it!
我认为您需要研究编写函数来完成这项工作,而不是在main()
程序中拥有所有代码,但是您仍然必须足够频繁地调用close()
。 / p>