简体   繁体   English

计算N次幂之和

[英]Calculating sum of N powers

This program should calculate the value of 2^1+2^2 + ... + 2^10: 该程序应计算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;
}

But when ie xecute the program, the father process prints 55. Why? 但是当执行该程序时,父进程将打印55。为什么?

The problem with above code is that the same pipe is used for writing and reading by the same process. 上面的代码的问题在于,同一进程使用相同的管道进行写入和读取。 (Here it is the parent process). (这是父进程)。

The parent passes the value to be computed to the child using pipe. 父级使用管道将要计算的值传递给子级。 The child writes the reply in the same pipe. 孩子将答复写在同一管道中。 The parent reads the ans back. 父母读回ans。 Here, you did not consider the case : parent writes value to the pipe and reads the reply back itself. 在这里,您没有考虑这种情况:父级将值写入管道,然后自己读取回复。 Hence the child never got the value. 因此,孩子永远不会获得价值。

To solve the above problem you must create two pipes : 要解决以上问题,您必须创建两个管道:

  1. pipe from parent to child 从父母到孩子的管道
  2. pipe from child to parent 从孩子到父母的管道

This will prevent the different race conditions and the code would be much more readable. 这将防止出现不同的竞争条件,并且代码将更具可读性。 Here is the code to do the same. 这是执行相同操作的代码。 PS : Since this may be a homework, I am not giving you the exact solution but giving an idea of the problem. PS:因为这可能是一项家庭作业,所以我没有给您确切的解决方案,而是给您提供了解决问题的方法。 Next time, please use english as the naming scheme. 下次,请使用英语作为命名方案。 This helps people debugging your code. 这可以帮助人们调试您的代码。

#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;
}

Interestingly enough, 55 is the sum of all the numbers from 1 to 10: that should give you an instant clue: 有趣的是,55是从1到10的所有数字的总和:这应该立即为您提供线索:

pipe() creates a pipe, a unidirectional data channel that can be used for interprocess communication. pipe()创建一个管道,一个可用于进程间通信的单向数据通道。 The array pipefd is used to return two file descriptors referring to the ends of the pipe. 数组pipefd用于返回两个引用管道末端的文件描述符。 pipefd[0] refers to the read end of the pipe. pipefd [0]指向管道的读取端。 pipefd[1] refers to the write end of the pipe. pipefd [1]指向管道的写端。

Note that well: unidirectional. 请注意: 单向。 In other words, the padre is reading back the same values it wrote (hence the 55). 换句话说,padre正在读回它写入的相同值(因此为55)。

You normally set up two pipes for bi-directional traffic, one for each direction. 通常,您为双向流量设置了两个管道,每个方向一个。 So I've double the number of pipes, using even ones for padre-to-child and odd ones for the other direction. 因此,我将管道数量增加了一倍,对偶数子代使用偶数管道,对另一个方向使用奇数管道。

In addition, your children continue with the padre loop whereas they should exit that loop immediately so their value of i is correct. 另外,您的孩子继续执行padre循环,而他们应该立即退出该循环,这样他们的i值是正确的。 You do have the loop exit based on padre but this happens after i has changed. 您确实有基于padre的循环退出,但是这 i更改发生。 You can either break where you set padre to false or simply i-- in the if(!padre) bit to restore i to the correct value for this child. 您可以打破你设置padre以虚假或干脆i--if(!padre)位,以恢复i为这个孩子正确的值。 I've done the latter. 我已经完成了后者。

The following code (with markers showing what changed) works okay: 以下代码(带有标记显示已更改的内容)可以正常工作:

#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;
}

This generates the correct answer of 2046, since 2 0 + 2 1 + ... 2 10 = 2 11 - 1 and, since you're leaving out the two-to-the-zero term (equal to 1): 2 1 + 2 2 + ... 2 10 is 2 11 - 2 (2 11 = 2048) . 这会产生2046的正确答案,因为2 0 + 2 1 + ... 2 10 = 2 11 - 1和,因为你留出两到了零项(等于1): 2 1 + 2 2 + ... 2 10 is 2 11 - 2 (2 11 = 2048)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM