无法在C/MPI中计算数组中大于x的数组元素

无法在C/MPI中计算数组中大于x的数组元素,c,mpi,C,Mpi,所以,我有一个问题,我有一个数组,我必须找到数组中大于索引k的数字的计数。因此,我实施了一个master-worker策略,其中我有一个负责I/O并将工作分配给工人的master。在主线程中,我创建了一个矩阵形状的数组,因此我可以轻松地将子数组传递给工作人员(我知道这听起来很奇怪)。然后在主线程中,我读取子数组输入的所有值,并将comp(比较值)设置为k索引值的值 然后我将工作部分大小、比较值和工作数据传递给所有线程(包括获得其工作份额的主线程)。最后,每个工作人员都完成自己的工作,并向主控台报

所以,我有一个问题,我有一个数组,我必须找到数组中大于索引
k
的数字的计数。因此,我实施了一个master-worker策略,其中我有一个负责I/O并将工作分配给工人的master。在主线程中,我创建了一个矩阵形状的数组,因此我可以轻松地将子数组传递给工作人员(我知道这听起来很奇怪)。然后在主线程中,我读取子数组输入的所有值,并将
comp
(比较值)设置为
k
索引值的值

然后我将工作部分大小、比较值和工作数据传递给所有线程(包括获得其工作份额的主线程)。最后,每个工作人员都完成自己的工作,并向主控台报告其结果,当从工作人员接收数据时,将其值添加到自己的值中,然后在屏幕上打印总结果

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <math.h>

int main(int argc, char *args[]){
    int rank, psize;
    MPI_Status status;
    MPI_Init(&argc, &args);
    MPI_Comm_size(MPI_COMM_WORLD, &psize);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    int *workvet, worksize, comp;
    
    if(rank == 0){

        int tam, k;
        int **subvets, portion;

        scanf("%d", &tam);
        scanf("%d", &k);
        
        portion = ceil((float)tam/(float)psize);

        subvets = malloc(sizeof(int) * psize);
        for(int i = 0; i < psize; i++)
            subvets[i] = calloc(portion, sizeof(int));
        for(int i = 0; i < psize; i++){
            for(int j = 0; j < portion; j++){
                if((i*j+j) < tam)
                    scanf("%d ", &subvets[i][j]);
                if((i*j+j) == k)
                    comp = subvets[i][j];
            }
        }
        
        for(int i = 1; i < psize; i++){
            MPI_Send(&portion, 1, MPI_INT, i, i, MPI_COMM_WORLD);
            MPI_Send(&comp, 1, MPI_INT, i, i, MPI_COMM_WORLD);
            MPI_Send(subvets[i], portion, MPI_INT, i, i, MPI_COMM_WORLD);
        }
        workvet = calloc(portion, sizeof(int));
        workvet = subvets[0];
        worksize = portion;
    } else {

        MPI_Recv(&worksize, 1, MPI_INT, 0, rank, MPI_COMM_WORLD, &status);
        MPI_Recv(&comp, 1, MPI_INT, 0, rank, MPI_COMM_WORLD, &status);
        workvet = calloc(worksize, sizeof(int));
        MPI_Recv(workvet, worksize, MPI_INT, 0, rank, MPI_COMM_WORLD, &status);
    }

    int maior = 0;
    for(int i = 0; i < worksize; i++){
        if(workvet[i] > comp)
            maior++;
    }
    
    if(rank == 0){
        int temp;
        for(int i = 1; i < psize; i++){
            MPI_Recv(&temp, 1, MPI_INT, i, rank, MPI_COMM_WORLD, &status);
            maior += temp;
        }
        printf("%d números maiores que %d", maior, comp);
    } else {
        MPI_Send(&maior, 1, MPI_INT, 0, rank, MPI_COMM_WORLD);
    }
    
    MPI_Finalize();
}

因此,我的程序应该计算有多少元素大于索引7的元素(对应于值8),在这种情况下,它应该返回2<代码>tam正在单元化

还有一些其他问题

您正在执行
scanf
以获取
comp
的值,但在其下方的循环中,您正在为其分配一个新值(即提示的值被丢弃)。如果原始值被视为默认值(如果循环无法分配新值),那么这可能非常好,但对我来说,这似乎有点不稳定

AFAICT,您正在尝试在所有进程中循环
workvet
。但是,对于客户端,这没有任何作用,因为您没有返回结果[见下文]

客户机正在发回
maior
,但他们从未计算过它的值。而且,main没有收到该值。它自己计算一个

maior
在您发布的代码中没有定义。因此,它是统一的[即使在主要方面]

看起来您希望客户机发回其计算值的单个标量值
maior
,但他们不进行计算

因此,客户机将主进程尝试求和的垃圾
maior
值发回

您正在向客户端发送
部分
,但客户端会将其作为
工作大小
接收。并且,在main发送后,它将
部分
分配给
工作大小
。我建议在所有地方使用相同的名称,以减少混淆

您没有提供任何示例数据,因此很难在此处进一步调试。部分问题在于,
subvets
中只有一些值是根据
if
[或它看起来是这样的…]用主中的
scanf
初始化的

因此,客户机将在给定的
subvet
数组中循环可能的单位化值[发送给作为
workvet
]接收它的客户机]

如果
subvet
的设置循环在发送哪些值方面是正确的(即,只发送某些选定的值),我不确定您是否可以使用现有的2D数组方法执行所需操作

如果没有一个描述输入数据的问题语句以及您想用它做什么,那么很难预测什么是正确的代码,但是

一些猜测

您正在计算所有进程中的
最高值
(在主进程中可能没有用),但是没有人用它做任何事情。我的猜测是,您只希望在客户端进程中计算此值。然后,将其作为
maior
发送回main

然后,main可以对所有客户端的
maior
值求和


更新:


实际上,我将
maior
更改为
highest
,以便在此处发布该问题,因此这有点道理(葡萄牙语中maior更大),但在所有情况下都没有这样做

正如我提到的,我猜了很多——不用担心。旁注:事实上,你的英语相当好。你能翻译代码真是太好了。有些人用英语发帖,但把代码留在他们的母语中。这会让事情慢一点。有时候,我把代码放进谷歌翻译,只是想弄明白它的意思


我只是在没有翻译的情况下更新了代码,以反映我正在进行的工作。因此,对于subvets部分,我实际上认为这是一个矩阵,其中我将把它的每一行作为一个数组发送给每个工作线程,if语句只在达到数组大小之前读取,因此,剩下的值为0(因为我使用了calloc,所以这种方法适合我必须解决的问题)

实际上不需要2D数组。只需填充一个1D数组,然后将不同的偏移量和计数放入单个数组中即可(见下文)

通过尝试在单个函数
main
中执行所有操作,这可能是导致分离主任务和辅助任务时出现一些问题的原因

通过将内容拆分为[更多]函数,这可以使事情变得更简单。我们可以在master和worker中为相同的数据使用相同的变量名,而不会产生任何命名冲突

还有一条很好的格言……不要复制代码

各种
MPI.*
调用需要很多参数,因为它们是通用的。将它们与包装函数隔离可以使事情更简单,调试更容易

请注意,
MPI\u Send/MPI\u Recv
的第二个参数是一个计数,而不是字节数(因此,不是
sizeof
)(即一个bug)。通过将它们放在包装函数中,可以在单个位置修复一次调用

我对分割逻辑做了一点小小的修改。在你的代码[AFAICT]中,你让主/主进程做了一些计算。这就是fi
10 // size
7  // k
1 2 3 4 5 6 7 8 9 10 // elements
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <math.h>

// _dbgprt -- debug print
#define _dbgprt(_fmt...) \
    do { \
        printf("%d: ",myrank); \
        printf(_fmt); \
    } while (0)

#ifdef DEBUG
#define dbgprt(_fmt...) \
    _dbgprt(_fmt)
#else
#define dbgprt(_fmt...) \
    do { \
    } while (0)
#endif

int myrank;                         // current rank
int numproc;                        // number of processes in comm group

// dataload -- read in the data
int *
dataload(FILE *xfsrc,int worksize)
{
    int *workvet;

    // get enough space
    workvet = calloc(worksize,sizeof(int));

    // fill the array
    for (int idx = 0;  idx < worksize;  ++idx)
        fscanf(xfsrc,"%d",&workvet[idx]);

    return workvet;
}

// docalc -- count number of values greater than limit
int
docalc(int *workvet,int worksize,int k)
{
    int count = 0;

    for (int idx = 0; idx < worksize; ++idx) {
        if (workvet[idx] > k)
            count += 1;
    }

    return count;
}

// sendint -- send some data
void
sendint(int rankto,int *data,int count)
{
    int tag = 0;

    // NOTE: second argument is an array _count_ and _not_ the number of bytes
    MPI_Send(data,count,MPI_INT,rankto,tag,MPI_COMM_WORLD);
}

// recvint -- receive some data
void
recvint(int rankfrom,int *data,int count)
{
    int tag = 0;
    MPI_Status status;

    MPI_Recv(data,count,MPI_INT,rankfrom,tag,MPI_COMM_WORLD,&status);
}

// worker -- perform all worker operations
void
worker(void)
{
    int master = 0;

    // get array count
    int worksize;
    recvint(master,&worksize,1);

    // get limit value
    int k;
    recvint(master,&k,1);

    // allocate space for data
    int *workvet = calloc(worksize,sizeof(int));

    // get that data
    recvint(master,workvet,worksize);

    // calculate number of elements higher than limit
    int count = docalc(workvet,worksize,k);

    // send back result
    sendint(master,&count,1);
}

// master -- perform all master operations
void
master(int argc,char **argv)
{
    int isfile;
    FILE *xfsrc;
    int workrank;

    // get the data either from stdin or from a file passed on the command line
    do {
        isfile = 0;
        xfsrc = stdin;

        if (argc <= 0)
            break;

        xfsrc = fopen(*argv,"r");
        if (xfsrc == NULL) {
            perror(*argv);
            exit(1);
        }

        isfile = 1;
    } while (0);

    // get number of data elements
    int worksize;
    fscanf(xfsrc,"%d",&worksize);

    // get limit [pivot]
    int k;
    fscanf(xfsrc,"%d",&k);

    dbgprt("master: PARAMS worksize=%d k=%d\n",worksize,k);

    // read in the data array
    int *workvet = dataload(xfsrc,worksize);
    if (isfile)
        fclose(xfsrc);

    // get number of workers
    // NOTE: we do _not_ have the master do calculations [for simplicity]
    // usually, for large data, we want the master free to control things
    int numworkers = numproc - 1;

    // get number of elements for each worker
    int workper = worksize / numworkers;

    dbgprt("master: LOOP numworkers=%d workper=%d\n",numworkers,workper);

    // send data to other workers
    int remain = worksize;
    int offset = 0;
    int portion;
    for (workrank = 1;  workrank < numproc;  ++workrank,
        offset += portion, remain -= portion) {
        // get amount for this worker
        portion = workper;

        // last proc must get all remaining work
        if (workrank == (numproc - 1))
            portion = remain;

        dbgprt("master: WORK/%d offset=%d portion=%d\n",
            workrank,offset,portion);

        // send the worker's data count
        sendint(workrank,&portion,1);

        // send the pivot point
        sendint(workrank,&k,1);

        // send the data to worker
        sendint(workrank,&workvet[offset],portion);
    }

    // accumulate count
    int total = 0;
    int count;
    for (workrank = 1;  workrank < numproc;  ++workrank) {
        recvint(workrank,&count,1);
        total += count;
    }

    printf("%d numbers bigger than %d\n",total,k);

    // do cross check of MPI result against a simple single process solution
#ifdef CHECK
    count = docalc(workvet,worksize,k);
    printf("master count was %d -- %s\n",
        count,(count == total) ? "PASS" : "FAIL");
#endif
}

// main -- main program
int
main(int argc,char **argv)
{

    MPI_Init(&argc,&argv);
    MPI_Comm_size(MPI_COMM_WORLD,&numproc);
    MPI_Comm_rank(MPI_COMM_WORLD,&myrank);

    // skip over program name
    --argc;
    ++argv;

    if (myrank == 0)
        master(argc,argv);
    else
        worker();

    MPI_Finalize();

    return 0;
}