该程序应计算2 ^ 1 + 2 ^ 2 + ... + 2 ^ 10:
的值#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <math.h>
#define N 10
// sommatoria per i che va da 1 a N di 2^i, ogni processo calcola un singolo valore
int main(int argc, char** argv)
{
pid_t figli[N];
unsigned int i;
int status;
int fd[N][2];
int msg1=0,msg2;
int risultato=0;
bool padre=true;
for(i=0;i<N && padre;i++)
{
pipe(fd[i]);
figli[i]=fork();
if(figli[i]<0)
{
fprintf(stderr,"Una fork ha fallito\n");
}
else if(figli[i]==0)
{
padre=false;
}
else
{
msg1=i+1;
write(fd[i][1],&msg1,sizeof(int));
}
}
if(!padre)
{
read(fd[i][0],&msg2,sizeof(int));
msg2=pow(2.0,msg2);
write(fd[i][1],&msg2,sizeof(int));
exit(0);
}
else
{
for(i=0;i<N;i++)
{
read(fd[i][0],&msg2,sizeof(int));
risultato+=msg2;
}
}
if(padre)
fprintf(stderr,"%d\n",risultato);
return 0;
}
但是当ie xecute程序时,父进程打印55。 为什么呢?
答案 0 :(得分:2)
上述代码的问题在于,相同的管道用于通过相同的过程进行写入和读取。 (这是父进程)。
父级使用管道将要计算的值传递给子级。孩子在同一个管道中写回复。父母读回ans。在这里,您没有考虑这种情况:父将值写入管道并自行读取回复。因此孩子从来没有得到这个价值。
要解决上述问题,您必须创建两个管道:
这将防止不同的竞争条件,并且代码将更具可读性。 这是执行相同操作的代码。 PS:因为这可能是一个功课,我不是给你确切的解决方案,而是提出问题的想法。下次,请使用英语作为命名方案。这有助于人们调试代码。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(void)
{
int msg;
int child_pid;
int parent_to_child[2];
int child_to_parent[2];
// my_pipe
int ret_val = pipe(parent_to_child);
if(ret_val!=0){
printf("pipe command failed !!\n");
exit(1);
}
// my_lock
ret_val = pipe(child_to_parent);
if(ret_val!=0){
printf("pipe command failed !!\n");
exit(1);
}
child_pid = fork();
if(child_pid==-1){
printf("fork() failed !!\n");
exit(1);
}else if(child_pid==0){
// i am child
read(parent_to_child[0], &msg, sizeof(int));
printf("child got %d from parent \n", msg);
msg = 34;
write(child_to_parent[1], &msg, sizeof(int));
}else{
// i am parent
msg = 24;
write(parent_to_child[1], &msg, sizeof(int));
//sleep(2);
read(child_to_parent[0], &msg, sizeof(int));
printf("parent got %d from child \n", msg);
}
return 0;
}
答案 1 :(得分:2)
有趣的是,55是1到10之间所有数字的总和:这应该会给你一个即时线索:
pipe()创建一个管道,一个可用于进程间通信的单向数据通道。数组pipefd用于返回引用管道末端的两个文件描述符。 pipefd [0]指的是管道的读取端。 pipefd [1]指的是管道的写端。
请注意:单向。换句话说,padre正在读回它写的相同值(因此55)。
您通常会为双向流量设置两个管道,每个方向一个。所以我的管道数量增加了一倍,对于另一个方向,使用偶数的管道和偶数的管道。
此外,您的孩子继续使用padre循环,而他们应该立即退出该循环,因此它们的i
值是正确的。您确实拥有基于padre
的循环退出,但在 i
发生更改后会发生。您可以将padre
设置为false的地方或仅i--
位中的if(!padre)
中断以将i
恢复为此子项的正确值。我做了后者。
以下代码(标记显示已更改的内容)可以正常工作:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <math.h>
#define N 10
int main(int argc, char** argv)
{
pid_t figli[N];
unsigned int i;
int status;
int fd[N*2][2]; // CHANGED: two unidirectional pipes
int msg1=0,msg2;
int risultato=0;
bool padre=true;
for(i=0;i<N && padre;i++)
{
pipe(fd[i*2]);
pipe(fd[i*2+1]); // ADDED: create second pipe
figli[i]=fork();
if(figli[i]<0)
{
fprintf(stderr,"Una fork ha fallito\n");
}
else if(figli[i]==0)
{
padre=false;
}
else
{
msg1=i+1;
write(fd[i*2][1],&msg1,sizeof(int)); // CHANGED: pipe number
}
}
if(!padre)
{
i--; // ADDED: to restore i for the child
read(fd[i*2][0],&msg2,sizeof(int)); // CHANGED: pipe number
msg2=pow(2.0,msg2);
write(fd[i*2+1][1],&msg2,sizeof(int)); // CHANGED: pipe number
exit(0);
}
else
{
for(i=0;i<N;i++)
{
read(fd[i*2+1][0],&msg2,sizeof(int)); // CHANGED: pipe number
risultato+=msg2;
}
}
if(padre)
fprintf(stderr,"%d\n",risultato);
return 0;
}
这会产生2046年的正确答案,因为20 + 21 + ... 210 = 211 - 1
因为你遗漏了两个零的术语(等于1):21 + 22 + ... 210 is 211 - 2 (211 = 2048)
。