计算N次幂的总和

时间:2012-04-03 08:21:51

标签: c fork

该程序应计算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。 为什么呢?

2 个答案:

答案 0 :(得分:2)

上述代码的问题在于,相同的管道用于通过相同的过程进行写入和读取。 (这是父进程)。

父级使用管道将要计算的值传递给子级。孩子在同一个管道中写回复。父母读回ans。在这里,您没有考虑这种情况:父将值写入管道并自行读取回复。因此孩子从来没有得到这个价值。

要解决上述问题,您必须创建两个管道:

  1. 从父母到孩子的管道
  2. 从孩子到父母的管道
  3. 这将防止不同的竞争条件,并且代码将更具可读性。 这是执行相同操作的代码。 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)