简体   繁体   English

MPI如何使在根进程中初始化的变量在其他进程中可见

[英]MPI How to make variables initialized in root process visible in other processes

I've got couple of test methods that initialize array a0 but the array differs in size with each method. 我有几个初始化数组a0的测试方法,但每个方法的数组大小不同。 These arrays are initialized in process rank==0. 这些数组在进程rank == 0中初始化。 Now in other file I have an implementation for a method that makes some computations using values from that table (it doesn't modify them). 现在在其他文件中,我有一个方法的实现,该方法使用该表中的值进行一些计算(它不会修改它们)。 It looks somewhat like this (pseudo code): 它看起来像这样(伪代码):

res=0;
x=0;
for(i=mystart;i<myend;++i)
  for(j=0;j<length;++j)
    x+= a[j] * multiplier;

MPI_Reduce(&x,&res,1,MPI_DOUBLE,MPI_SUM,0,MPI_COMM_WORLD);

I have a requirement that those computations can only be processed by processes other than root, but since they don't see what values does a[] hold, it doesn't work. 我有一个要求,这些计算只能由root以外的进程处理,但是由于它们看不到a []保留什么值,因此它不起作用。 I tried MPI_Bcast(a, ?, MPI_DOUBLE, 0, MPI_COMM_WORLD), but I can't get value of the size, since it differes with every method call. 我尝试了MPI_Bcast(a,?,MPI_DOUBLE,0,MPI_COMM_WORLD),但是我无法获取大小的值,因为每个方法调用都不同。 The whole code is kinda big but if someone wants to take a look I can publish it somewhere... 整个代码有点大,但是如果有人想看一看,我可以将其发布到某处...

Is there an easy way to make those fields visible to the other processes? 有没有一种简便的方法可以使这些字段对其他进程可见?

EDIT: As suggested I uploaded the code: main func: http://pastebin.com/tREeHMZM methods for comutation and class declaration: http://pastebin.com/BBedJ7bA 编辑:根据建议,我上传了代码:main func: http ://pastebin.com/tREeHMZM用于转换和类声明的方法: http ://pastebin.com/BBedJ7bA

Dividing the loops works fine it's just those comptations that don't work, and I'm not sure how to make those processes communicate with each other. 划分循环可以很好地解决问题,只是这些补偿无效,而且我不确定如何使这些进程相互通信。

为什么不广播要首先广播的阵列的大小?

You were really quite close. 你真的很亲密。 I believe I was able to correct the program and the corrected text is below. 我相信我能够更正该程序,更正后的文本如下。

Note: I started writing this explanation before I actually modified the program, so replace "you must do" with "I did" 注意:在实际修改程序之前,我已经开始编写此说明,因此将“您必须做”替换为“我做过”

I was able to download and build your program. 我能够下载并构建您的程序。 I was able to work around the missing Function.h , based on what I already had by changing Function::value into just Function_value [a global function]. 我可以通过将Function::value更改为Function_value [一个全局函数]来解决丢失的Function.h

The one thing you do have to do is have rank 0 get the random seed value. 要做的一件事是让等级0获得随机种子值。 It has to bcast this first , so the client ranks can get it so their calls to shuffle will produce the same results. 它必须首先对此进行bcast,以便客户端等级可以得到它,因此他们的shuffle呼叫将产生相同的结果。 So, I created a global ranseed , set from a bcast in main , that shuffle can see it. 因此,我从main的bcast创建了一个全局ranseed ,设置为shuffle可以看到它。

I changed the test* routines to always compute x0 , y0 , a , and c , regardless of rank. 我更改了test*例程,以始终计算x0y0ac ,而不管其排名如何。 Otherwise, the compiler was complaining about possibly uninitialized values for those pointers. 否则,编译器会抱怨这些指针可能未初始化的值。 The computation is small. 计算量很小。 No need to broadcast these values. 无需广播这些值。 If this precalculation were intensive [which it isn't], then bcast-ing the arrays would be the way to go. 如果这种预先计算是密集的(不是),那么对数组进行bcast处理将是可行的方法。

I think you already realized this in the MPI version of calcError because you were commenting out the bcasts for these arrays. 我认为您已经在MPI版本的calcError实现了这一点,因为您正在注释掉这些数组的bcast。

AFAICT, your MPI calcError looks good except for two things: AFAICT, 除了以下两点外,您的MPI calcError看起来不错:

(1) The MPI_Reduce call should not be inside the if (myid_c >= 0) block. (1) MPI_Reduce呼叫不应内侧if (myid_c >= 0)的块。 I think it needs to be at the bottom after this block (ie even rank 0 needs to call it). 我认为它必须位于此块之后的底部(即,即使等级0也需要调用它)。

(2) In the old place for the MPI_Reduce [inside the if ], I think you need an error_p = error; (2)在MPI_Reduce位置[ if里面],我认为您需要一个error_p = error; after the double level for loops because error_p is the value that the clients send [and error is what the root receives ] 在双级for循环之后,因为error_p是客户端发送的值[而error是根接收到的值 ]

I added a -R command line option to allow manual setting the of the random seed value. 我添加了-R命令行选项,以允许手动设置随机种子值。 I also added a -M option to switch between the MPI and non-MPI versions of calcError 我还添加了-M选项以在MPI版本和calcError非MPI版本之间calcError

I've run the program using the mpi mode: mpirun -np 8 <program> -M and all tests seemed to work. 我已经使用mpi模式运行了该程序: mpirun -np 8 <program> -M并且所有测试似乎都可以工作。 I did ctrl-c on testL after a while, so no guarantees on that. 一段时间后,我在testLtestLctrl-c ,因此无法保证。


Here's a single [archive] file, similar to your paste, the file separater line is % <filename> 这是一个[存档]文件,类似于您的粘贴,文件分隔符行为% <filename>

It has all my outlined corrections [please pardon the gratuitous style cleanup]. 它具有我概述的所有更正[请原谅免费的样式清理]。

Warning: Be careful when extracting Function.h as I had to create a skeleton version, so if your version has a class definition, it will get lost. 警告:解压缩Function.h时要小心,因为我必须创建一个框架版本,因此,如果您的版本具有类定义,它将丢失。

% Error.h
// mpisize/Error.h -- Error class

#ifndef _mpisize_Error_h_
#define _mpisize_Error_h_

class Error {
  private:
    double *v;
    double *x0;
    double *y0;
    double *a;
    double *c;
    int length;                         // grid length
    double length_2;
    double mult;
    int size;                           // number of gausses to add
    double error;

  public:
    void setValues(double *v, int length, double mult);
    void setCoefficients(double *x0,double *y0, double *a,double *c, int size);
    void calcError(int mpiflg);
    void calcErrorStd();
    void calcErrorMpi();
    double getError();
};

#endif
% Function.h
// mpisize/Function.h -- Function class

#ifndef _mpisize_Function_h_
#define _mpisize_Function_h_

#include <math.h>

//Function code
double
Function_value(double x, double y, double x0, double y0, double a, double c);

#endif
% mpisize.h
// mpisize/mpisize.h -- Function class

#ifndef _mpisize_mpisize_h_
#define _mpisize_mpisize_h_

#include <math.h>
#include "Error.h"
#include "Function.h"

#ifdef _MPISIZE_GLO_
#define EXTRN_MPISIZE       /**/
#else
#define EXTRN_MPISIZE       extern
#endif

EXTRN_MPISIZE int opt_debug;
EXTRN_MPISIZE int opt_send;
EXTRN_MPISIZE int glob_rank;
EXTRN_MPISIZE double tvzero;

double
tvgetf(void);

int
dbgif(int lvl);

void
_dbgprt(const char *fmt,...);

#define dbgprt(_lvl,_fmt...) \
    do { \
        if (dbgif(_lvl)) \
            _dbgprt(_fmt); \
    } while (0)

#endif
% ErrMpi.cpp
// mpisize/ErrMpi -- MPI threaded version of calcError

#include <iostream>
#include <math.h>
#include <mpi.h>
#include "mpisize.h"

void
Error::calcErrorMpi()
{
    int mystart, myend;
    int myid, myid_c;
    int numproc, numproc_c;

    //MPI_Comm_rank(MPI_COMM_WORLD, &myid);
    myid = glob_rank;
    MPI_Comm_size(MPI_COMM_WORLD, &numproc);

    myid_c = myid - 1;
    numproc_c = numproc - 1;

    // NOTE/BUG: length_2 is double, so it needs MPI_DOUBLE
#if 0
    MPI_Bcast(&length, 1, MPI_INT, 0, MPI_COMM_WORLD);
    // MPI_Bcast(&length_2, 1, MPI_INT, 0, MPI_COMM_WORLD);  // broken
    // MPI_Bcast(&length_2, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);  // fixed
#endif

    MPI_Bcast(&error, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
    // MPI_Bcast(v, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);

    MPI_Bcast(&size, 1, MPI_INT, 0, MPI_COMM_WORLD);
    MPI_Bcast(&mult, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);

    // NOTE/BUG: these are arrays, so second argument must be array count
    if (opt_send) {
        MPI_Bcast(x0, size, MPI_DOUBLE, 0, MPI_COMM_WORLD);
        MPI_Bcast(y0, size, MPI_DOUBLE, 0, MPI_COMM_WORLD);
        MPI_Bcast(a, size, MPI_DOUBLE, 0, MPI_COMM_WORLD);
        MPI_Bcast(c, size, MPI_DOUBLE, 0, MPI_COMM_WORLD);
    }

    double error_p = 0;

    error = 0;

    if (myid_c >= 0) {
        mystart = (length / numproc_c) * myid_c;

        if (length % numproc_c > myid_c) {
            mystart += myid_c;
            myend = mystart + (length / numproc_c) + 1;
        }
        else {
            mystart += length % numproc_c;
            myend = mystart + (length / numproc_c);
        }

        dbgprt(2,"calcErrorMpi: STARTUP myid_c=%d numproc_c=%d length=%d length_2=%g mystart=%d myend=%d\n",
            myid_c,numproc_c,length,length_2,mystart,myend);

        double dv;
        double vtmp;

        for (int i = mystart; i < myend; i++) {
            for (int j = 0; j < length; j++) {
                vtmp = 0.0;
                for (int k = 0; k < size; k++)
                    vtmp += Function_value((i - length_2) * mult,
                        (j - length_2) * mult,
                        x0[k], y0[k], a[k], c[k]);
                dv = v[i * length + j] - vtmp;
                error += dv * dv;
            }
        }

        error_p = error;

        // if(myid == 0 ) cout << "Proces " << myid << " after reducing error = " << error << endl;

    }

    dbgprt(2,"calcErrorMpi: RED/BEF error_p=%g error=%g\n",error_p,error);
    MPI_Reduce(&error_p, &error, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
    dbgprt(2,"calcErrorMpi: RED/AFT error_p=%g error=%g\n",error_p,error);
}
% Error.cpp
// mpisize/Error -- Error routines

#include <iostream>
#include <math.h>
#include "Error.h"
#include "Function.h"

using namespace std;

void
Error::setValues(double *v, int length, double mult)
{
    this->v = v;
    this->length = length;
    this->mult = mult;
    length_2 = length * 0.5;
    cout << "test" << endl;
}

void
Error::setCoefficients(double *x0, double *y0, double *a, double *c, int size)
{
    this->x0 = x0;
    this->y0 = y0;
    this->a = a;
    this->c = c;
    this->size = size;
}

void
Error::calcErrorStd()
{
    double dv;
    double vtmp;

    error = 0;

    for (int i = 0; i < length; i++) {
        for (int j = 0; j < length; j++) {
            vtmp = 0.0;
            for (int k = 0; k < size; k++)
                vtmp += Function_value((i - length_2) * mult,
                    (j - length_2) * mult,
                    x0[k], y0[k], a[k], c[k]);
            dv = v[i * length + j] - vtmp;
            error += dv * dv;
        }
    }
}

void
Error::calcError(int mpiflg)
{

    if (mpiflg)
        calcErrorMpi();
    else
        calcErrorStd();
}

double
Error::getError()
{
    return sqrt(error);
}
% Function.cpp
// mpisize/Function -- function code

#include "Function.h"

// Function code
double
Function_value(double x, double y, double x0, double y0, double a, double c )
{
   return a * exp(-((x - x0) * (x - x0) + (y - y0) * (y - y0)) * c);
}
% mpisize.cpp
// mpisize/mpisize -- main program and test routines

#define _MPISIZE_GLO_
#include "mpisize.h"
#include "Error.h"
#include "Function.h"

#include <iostream>
#include <mpi.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/time.h>
#include <math.h>

using namespace std;

const int LEN = 1250;
const int LEN_2 = LEN / 2;
const int SIZE = LEN * LEN;
const int SHUFFLE_TIMES = 2 * SIZE;
const double MULT = 0.1;
const int COMPLEXITY = 8;

int ranseed;
int opt_mpi;

double
generate(double x, double y, double *x0, double *y0, double *a, double *c, int indexS, int indexE)
{
    double v = 0.0;

    for (int i = indexS; i < indexE; i++) {
        v += Function_value(x, y, x0[i], y0[i], a[i], c[i]);
    }
    return v;
}

void
generate(double *v, double *x0, double *y0, double *a, double *c)
{
    for (int i = 0; i < LEN; i++)
        for (int j = 0; j < LEN; j++)
            v[i * LEN + j] = generate((i - LEN_2) * MULT, (j - LEN_2) * MULT,
                x0, y0, a, c, 0, COMPLEXITY);
}

void
shuffle(double *v)
{
    // losowo przestawiamy polozenia czastek
    int i;
    int j;
    double vtmp;

    srandom(ranseed);

    for (int k = 0; k < SHUFFLE_TIMES; k++) {
        i = random() % SIZE;
        j = random() % SIZE;

        vtmp = v[i];

        v[i] = v[j];
        v[i] = vtmp;
    }
}

void
test(const char *testname,Error *err, double errorExpected)
{

    err->calcError(opt_mpi);

    double error;

    if (glob_rank == 0) {
        error = err->getError();
        cout << endl << "Test " << testname << " blad " << error << endl;

        if (fabs(error - errorExpected) > (0.001 + 0.001 * errorExpected)) {
            cerr << "Blad powinno byc " << errorExpected << endl;
            MPI_Finalize();
            exit(0);
        }
        else {
            cout << " - - - - - - OK" << endl;
        }
    }
}

void
test1(Error *err)
{

    double x0[] = { -3, -2, -2, -1, 1, 2, 2, 3 };
    double y0[] = { -3, -3, 3, -1, 1, -3, 3, 3 };
    double a[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    double c[] = { 0.1, 0.05, 0.02, 0.01, 0.01, 0.01, 0.02, 0.05 };

    err->setCoefficients(x0, y0, a, c, 8);

    test("test1", err, 0);
}

void
test2(Error *err)
{

    double x0[] = { -3, -1, -2, -1, 1, 2, 2, 3, 1, 2, 3, 4, 5, 6, 7 };
    double y0[] = { -3, -3, 3, -1, 1, -3, 1, 3, 1, 2, 3, 4, 1, 2, 3 };
    double a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 1, 2, 3 };
    double c[] = { 0.1, 0.05, 0.02, 0.01, 0.02, 0.01, 0.02, 0.05, 1, 1, 1, 1, 1, 2, 3 };

    err->setCoefficients(x0, y0, a, c, 15);

    test("test2", err, 357.729);
}

void
test3(Error *err)
{

    double x0[] = { -3, -1, -2, -1, 1, 2, 2, 3, -3, -1, -2, -1, 1, 2, 2, 3, 1, 2, 3, 4, 5, 6, 7, -3, -1, -2, -1, 1, 2, 2, 3, 1, 2, 3, 4, 5, 6, 7 };
    double y0[] = { -3, -3, 3, -1, 1, -3, 1, 3, -3, -1, -2, -1, 1, 2, 2, 3, 1, 2, 3, 4, 5, 6, 7, -3, -1, -2, -1, 1, 2, 2, 3, 1, 2, 3, 4, 5, 6, 7 };
    double *a = new double[38];
    double *c = new double[38];

    for (int i = 0; i < 38; i++) {
        a[i] = 1 + i / 38.0;
        c[i] = 2 + i / 38.0;
    }

    err->setCoefficients(x0, y0, a, c, 38);

    test("test3", err, 2975.86);
}

void
test4(Error *err)
{

    double *x0 = new double[150];
    double *y0 = new double[150];
    double *a = new double[150];
    double *c = new double[150];

    for (int i = 0; i < 150; i++) {
        x0[i] = 5 - i * 0.2;
        a[i] = 1 + i / 8.0;
        y0[i] = 2 - i * 0.22;
        c[i] = 2 + i / 38.0;
    }

    err->setCoefficients(x0, y0, a, c, 150);

    test("test4", err, 3303.04);
}

void
testL(Error *err)
{
    double *x0;
    double *y0;
    double *a;
    double *c;

    if (glob_rank == 0)
        cout << "Test pozwalajacy na oszacowanie przyspieszenia" << endl;

    x0 = new double[111];
    y0 = new double[111];
    a = new double[111];
    c = new double[111];

    for (int i = 0; i < 111; i++) {
        x0[i] = 5 - i * 0.2;
        a[i] = 1 + i / 1.1;
        y0[i] = 2 - i * 0.4;
        c[i] = 2 + i / 38.0;
    }

    double toterror = 0;
    double error;

    for (int i = 0; i < 20; i++) {
        a[i] = i;
        err->setCoefficients(x0, y0, a, c, 111 - i * 3);

        err->calcError(opt_mpi);

        error = err->getError();
        dbgprt(2,"testL: POST error=%g\n",error);

        if (glob_rank == 0) {
            toterror += error;
        }
    }

    if (glob_rank == 0)
        cout << "Uwaga: ta wartosc nie moze zalezec od liczby uzytych procesow = " << toterror << endl;
}

int
main(int ac, char **av)
{
    char *cp;

    MPI_Init(&ac, &av);

    MPI_Comm_rank(MPI_COMM_WORLD, &glob_rank);

#if 1
    ranseed = 123767832;
#else
    ranseed = 0;
#endif

    --ac;
    ++av;

    for (;  ac > 0;  --ac, ++av) {
        if (glob_rank != 0)
            break;

        cp = *av;
        if (*cp != '-')
            break;

        switch (cp[1]) {
        case 'd':
            opt_debug = 1;
            break;

        case 'M':
            opt_mpi = 1;
            break;

        case 'R':
            ranseed = atoi(cp + 2);
            break;

        case 'S':
            opt_send = 1;
            break;
        }
    }

    tvzero = tvgetf();

    if (ranseed == 0)
        ranseed = time(NULL);
    if (glob_rank == 0) {
        cout << "Random: " << ranseed << std::endl;
        cout << "Mpi: " << opt_mpi << std::endl;
        cout << "Send: " << opt_send << std::endl;
        cout << "Debug: " << opt_debug << std::endl;
    }

    MPI_Bcast(&tvzero, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
    MPI_Bcast(&ranseed, 1, MPI_INT, 0, MPI_COMM_WORLD);
    MPI_Bcast(&opt_mpi, 1, MPI_INT, 0, MPI_COMM_WORLD);
    MPI_Bcast(&opt_send, 1, MPI_INT, 0, MPI_COMM_WORLD);
    MPI_Bcast(&opt_debug, 1, MPI_INT, 0, MPI_COMM_WORLD);

    Error *err = new Error();
    double *v;

    v = new double[SIZE];
    double x0[] = { -3, -2, -2, -1, 1, 2, 2, 3 };
    double y0[] = { -3, -3, 3, -1, 1, -3, 3, 3 };
    double a[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    double c[] = { 0.1, 0.05, 0.02, 0.01, 0.01, 0.01, 0.02, 0.05 };

    generate(v, x0, y0, a, c);
    shuffle(v);

    // udostepniam dane dla procesu = 0
    err->setValues(v, LEN, MULT);

    test1(err);
    test2(err);
    test3(err);
    test4(err);
    test1(err);

    testL(err);

    MPI_Finalize();

    return 0;
}

double
tvgetf(void)
{
    struct timespec ts;
    double sec;

    clock_gettime(CLOCK_REALTIME,&ts);

    sec = ts.tv_nsec;
    sec /= 1e9;
    sec += ts.tv_sec;

    return sec;
}

int
dbgif(int lvl)
{
    int goflg = 0;

    do {
        if (! opt_debug)
            break;

        if (glob_rank == 0) {
            goflg = 1;
            break;
        }

        if (lvl > opt_debug)
            goflg = 1;
    } while (0);

    return goflg;
}

void
_dbgprt(const char *fmt,...)
{
    va_list ap;
    double tvnow;

    tvnow = tvgetf();
    tvnow -= tvzero;

    printf("%.9f/%d ",tvnow,glob_rank);

    va_start(ap,fmt);
    vprintf(fmt,ap);
    va_end(ap);
}

UPDATE: 更新:

I've updated my full code example above to add tracing. 我已经更新了上面的完整代码示例以添加跟踪。 It seems to work in all cases. 它似乎在所有情况下都有效。

However, to answer your followup questions ... 但是,要回答您的后续问题...

what if I cannot modify the main class? 如果我不能修改主类怎么办?

I presume you mean "main file" which includes the test* functions? 我想您的意思是包含test*函数的“主文件”? No. You must modify the test* functions because they are the source of the bugs you're having. 不能。您必须修改test*函数,因为它们是您所遇到的错误的根源。

If I had to only modify Error, would it work if I moved out the MPI_reduce out of those loops, and added error = error_p at the end of the if statement as you suggested? 如果只需要修改Error,那么如果我将MPI_reduce移出这些循环,并按照您的建议在if语句的末尾添加了error = error_p ,是否可以工作?

Mostly, but you want error_p = error instead. 通常,但是您想error_p = error Reread my comment about this in my original post and reread the documentation for MPI_Reduce . 重新阅读我在原始帖子中对此的评论,并重新MPI_Reduce的文档。 First arg is what client sends to root and second arg is how root gets the value. 第一个arg是客户端发送给root的对象,第二个arg是root如何获取值的对象。

Interesting enough I'm also not able to broadcast length_2. 足够有趣的是,我也无法播放length_2。

That's because you were using MPI_INT instead of MPI_DOUBLE 那是因为你用MPI_INT代替MPI_DOUBLE

Then I guess I'd have to add all those Bcasts, but even if I broadcast the size value I dont know how to set the second parameter of the Bcast function for the rest of the arrays. 然后,我猜我必须添加所有这些Bcast,但是即使广播大小值,我也不知道如何为其余数组设置Bcast函数的第二个参数。 Everything I try ends with segmentation fault. 我尝试的一切都以细分错误结尾。

You do not need to broadcast the x0 et. 并不需要广播的x0等。 al. 人。 arrays if you always set them in test*, regardless of rank. 数组,如果您始终将它们设置为test *,则与排名无关 Remember that I mentioned that the calculation was small enough to be able to be repeated in all ranks 记住,我提到计算量很小,可以在所有等级中重复

Not setting them in all ranks is the bug. 就不一一在所有队伍中错误。

As expected, no matter what I try, I'm not able to broadcast any array to the rest of the processes. 不出所料,无论我尝试什么,我都无法向其余过程广播任何数组。

The broadcast part is working fine (ie rank 0 is sending the data correctly). 广播部分工作正常(即等级0正在正确发送数据)。 But, the non-root ranks have no place to store it and you're getting segfaults. 但是,非根目录级别无处存储它,并且您会遇到段错误。

Here is your test4 : 这是您的test4

void
test4(Error * err, int rank)
{

    if (rank == 0) {
        double *x0 = new double[150];
        double *y0 = new double[150];
        double *a = new double[150];
        double *c = new double[150];

        for (int i = 0; i < 150; i++) {
            x0[i] = 5 - i * 0.2;
            a[i] = 1 + i / 8.0;
            y0[i] = 2 - i * 0.22;
            c[i] = 2 + i / 38.0;
        }

        err->setCoefficients(x0, y0, a, c, 150);
    }

    test(err, 3303.04, rank);
}

Here is the modified version: 这是修改后的版本:

void
test4(Error * err, int rank)
{
    double *x0 = new double[150];
    double *y0 = new double[150];
    double *a = new double[150];
    double *c = new double[150];

    for (int i = 0; i < 150; i++) {
        x0[i] = 5 - i * 0.2;
        a[i] = 1 + i / 8.0;
        y0[i] = 2 - i * 0.22;
        c[i] = 2 + i / 38.0;
    }

    err->setCoefficients(x0, y0, a, c, 150);

    test(err, 3303.04, rank);
}

In my version, setCoefficients is always being called. 在我的版本中, 总是调用setCoefficients So, the non-root rank Error class will always have valid [non-null] pointers for x0 , etc. 因此,非根级别Error类将始终具有x0等的有效[non-null]指针。

In your version, setCoefficients is only called for the root rank. 在您的版本中, setCoefficients 用于根排名。 So, the non-root ranks will always have null pointers for x0 , etc. Thus, you'll get a segfault. 因此,非根目录行将始终具有x0等的空指针。这样,您将得到一个段错误。

Note that if you had compiled with -Wall , some of the test* functions would have been flagged with warnings about possibly uninitialized values. 请注意,如果您使用-Wall进行编译,则某些test*函数将被标记有关可能未初始化的值的警告。 Fixing those would probably have put you on to the problem earlier. 解决这些问题可能会使您更早地解决问题。

At a minimum, even if you wish to bcast x0 et. 至少,即使您希望广播x0等。 al., you must still ensure the child ranks have valid/sufficient space allocated. Al。,您仍然必须确保子等级已分配有效/足够的空间。

To achieve this, here's a modified test4 : 为了达到这个目的,这是一个修改后的test4

void
test4(Error * err, int rank)
{

    if (rank == 0) {
        double *x0 = new double[150];
        double *y0 = new double[150];
        double *a = new double[150];
        double *c = new double[150];

        for (int i = 0; i < 150; i++) {
            x0[i] = 5 - i * 0.2;
            a[i] = 1 + i / 8.0;
            y0[i] = 2 - i * 0.22;
            c[i] = 2 + i / 38.0;
        }

        err->setCoefficients(x0, y0, a, c, 150);
    }
    else
        err->setBuffers(150);

    test(err, 3303.04, rank);
}

And, you'll need something like: 并且,您将需要以下内容:

void
Error::setBuffers(int size)
{

    this->x0 = realloc(this->x0,sizeof(double) * size);
    this->y0 = realloc(this->y0,sizeof(double) * size);
    this->a = realloc(this->a,sizeof(double) * size);
    this->c = realloc(this->c,sizeof(double) * size);

    this->size = size;
}

So, after doing all that, you end up with a more complicated solution and you still have to modify test* . 因此,完成所有这些操作之后,您将得到一个更复杂的解决方案,并且仍然需要修改test*

Of course, in the MPI version of calcError , you'd want to do: 当然,在MPI版本的calcError ,您需要执行以下操作:

MPI_Bcast(x0, size, MPI_DOUBLE, 0, MPI_COMM_WORLD);

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

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