Расчет суммы N степеней - PullRequest
0 голосов
/ 03 апреля 2012

Эта программа должна вычислить значение 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;
}

Но когда выполняется программа, то процесс-отец печатает 55. Почему?

Ответы [ 2 ]

2 голосов
/ 03 апреля 2012

Интересно, что 55 - это сумма всех чисел от 1 до 10: это должно дать вам мгновенную подсказку:

pipe () создает канал, однонаправленный канал данных, который можно использовать для межпроцессного взаимодействия. Массив pipefd используется для возврата двух файловых дескрипторов, относящихся к концам канала. pipefd [0] относится к концу чтения канала. pipefd [1] относится к концу записи канала.

Обратите внимание, что хорошо: однонаправлено. Другими словами, падре считывает те же значения, которые он записал (отсюда и 55).

Обычно вы устанавливаете две трубы для двунаправленного трафика, по одному для каждого направления. Поэтому я удвоил число каналов, используя четные для падре-ребенку и нечетные для другого направления.

Кроме того, ваши дети продолжают работу с циклом Падре, тогда как они должны немедленно выйти из этого цикла, чтобы их значение 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, начиная с 2<sup>0</sup> + 2<sup>1</sup> + ... 2<sup>10</sup> = 2<sup>11</sup> - 1 и, так как вы опускаете член с нулем (равный 1): 2<sup>1</sup> + 2<sup>2</sup> + ... 2<sup>10</sup> is 2<sup>11</sup> - 2 (2<sup>11</sup> = 2048).

2 голосов
/ 03 апреля 2012

Проблема с приведенным выше кодом заключается в том, что один и тот же канал используется для записи и чтения одним и тем же процессом. (Здесь это родительский процесс).

Родитель передает значение, которое будет вычислено, дочернему элементу, используя pipe. Ребенок пишет ответ в той же трубе. Родитель читает ответ. Здесь вы не учли случай: parent записывает значение в канал и сам читает ответ. Следовательно, ребенок никогда не получил ценность.

Для решения вышеуказанной проблемы необходимо создать две трубы:

  1. труба от родителя к ребенку
  2. канал от ребенка к родителю

Это предотвратит различные условия гонки, и код станет намного более читабельным. Вот код, чтобы сделать то же самое. 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...