C 简单MPI发送/接收程序中行为不明确

C 简单MPI发送/接收程序中行为不明确,c,mpi,worker,C,Mpi,Worker,我的代码中有一个bug已经有一段时间了,现在还不知道如何解决它 我试图实现的是非常简单的:每个工作节点(即秩!=0的节点)在一个方形结构中获得一行(由一维arry表示),该结构涉及一些计算。一旦计算完成,这一行将被发送回主机 出于测试目的,不涉及任何计算。所发生的一切是: master将行号发送给worker,worker使用行号计算相应的值 worker将返回带有结果值的数组 现在,我的问题是: 对于一行中的元素数量(大小=1006)和工人数量>1,所有工程按预期达到一定大小 如果一行中

我的代码中有一个bug已经有一段时间了,现在还不知道如何解决它

我试图实现的是非常简单的:每个工作节点(即秩!=0的节点)在一个方形结构中获得一行(由一维arry表示),该结构涉及一些计算。一旦计算完成,这一行将被发送回主机

出于测试目的,不涉及任何计算。所发生的一切是:

  • master将行号发送给worker,worker使用行号计算相应的值
  • worker将返回带有结果值的数组
现在,我的问题是:

  • 对于一行中的元素数量(大小=1006)和工人数量>1,所有工程按预期达到一定大小
  • 如果一行中的元素超过1006,工人无法关机,程序不会终止
  • 仅当我尝试将阵列发送回主阵列时才会发生这种情况。如果我只是返回一个INT,那么一切都正常(请参阅doMasterTasks()和doWorkerTasks()中注释掉的行)
基于最后一点,我假设一定存在某种竞争条件,只有当要发送回主机的数组达到一定大小时才会出现这种竞争条件

你知道问题是什么吗

使用以下代码编译:mpicc-O2-std=c99-osimple

像这样运行可执行文件:mpirun-np3 simple(例如1006或1007)

代码如下:

#include "mpi.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MASTER_RANK 0
#define TAG_RESULT 1
#define TAG_ROW 2
#define TAG_FINISHOFF 3

int mpi_call_result, my_rank, dimension, np;

// forward declarations
void doInitWork(int argc, char **argv);
void doMasterTasks(int argc, char **argv);
void doWorkerTasks(void);
void finalize();
void quit(const char *msg, int mpi_call_result);

void shutdownWorkers() {
    printf("All work has been done, shutting down clients now.\n");
    for (int i = 0; i < np; i++) {
        MPI_Send(0, 0, MPI_INT, i, TAG_FINISHOFF, MPI_COMM_WORLD);
    }
}

void doMasterTasks(int argc, char **argv) {
    printf("Starting to distribute work...\n");
    int size = dimension;
    int * dataBuffer = (int *) malloc(sizeof(int) * size);

    int currentRow = 0;
    int receivedRow = -1;
    int rowsLeft = dimension;
    MPI_Status status;

    for (int i = 1; i < np; i++) {
        MPI_Send(&currentRow, 1, MPI_INT, i, TAG_ROW, MPI_COMM_WORLD);
        rowsLeft--;
        currentRow++;

    }

    for (;;) {
//        MPI_Recv(dataBuffer, size, MPI_INT, MPI_ANY_SOURCE, TAG_RESULT, MPI_COMM_WORLD, &status);
        MPI_Recv(&receivedRow, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);

        if (rowsLeft == 0)
            break;

        if (currentRow > 1004)
            printf("Sending row %d to worker %d\n", currentRow, status.MPI_SOURCE);
        MPI_Send(&currentRow, 1, MPI_INT, status.MPI_SOURCE, TAG_ROW, MPI_COMM_WORLD);
        rowsLeft--;
        currentRow++;
    }
    shutdownWorkers();
    free(dataBuffer);
}

void doWorkerTasks() {
    printf("Worker %d started\n", my_rank);

    // send the processed row back as the first element in the colours array.
    int size = dimension;
    int * data = (int *) malloc(sizeof(int) * size);
    memset(data, 0, sizeof(size));

    int processingRow = -1;
    MPI_Status status;

    for (;;) {

        MPI_Recv(&processingRow, 1, MPI_INT, 0, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
        if (status.MPI_TAG == TAG_FINISHOFF) {
            printf("Finish-OFF tag received!\n");
            break;
        } else {
//            MPI_Send(data, size, MPI_INT, 0, TAG_RESULT, MPI_COMM_WORLD);
            MPI_Send(&processingRow, 1, MPI_INT, 0, TAG_RESULT, MPI_COMM_WORLD);
        }
    }

    printf("Slave %d finished work\n", my_rank);
    free(data);
}

int main(int argc, char **argv) {


    if (argc == 2) {
        sscanf(argv[1], "%d", &dimension);
    } else {
        dimension = 1000;
    }

    doInitWork(argc, argv);

    if (my_rank == MASTER_RANK) {
        doMasterTasks(argc, argv);
    } else {
        doWorkerTasks();
    }
    finalize();
}

void quit(const char *msg, int mpi_call_result) {
    printf("\n%s\n", msg);
    MPI_Abort(MPI_COMM_WORLD, mpi_call_result);
    exit(mpi_call_result);
}

void finalize() {
    mpi_call_result = MPI_Finalize();
    if (mpi_call_result != 0) {
        quit("Finalizing the MPI system failed, aborting now...", mpi_call_result);
    }
}

void doInitWork(int argc, char **argv) {
    mpi_call_result = MPI_Init(&argc, &argv);
    if (mpi_call_result != 0) {
        quit("Error while initializing the system. Aborting now...\n", mpi_call_result);
    }
    MPI_Comm_size(MPI_COMM_WORLD, &np);
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
}
#包括“mpi.h”
#包括
#包括
#包括
#定义MASTER_秩0
#定义TAG_结果1
#定义第2行的标记
#定义标记_FINISHOFF 3
int mpi调用结果、我的秩、维数、np;
//转发声明
void doInitWork(int argc,char**argv);
void-doMasterTasks(int-argc,char**argv);
无效工作任务(无效);
void finalize();
void quit(const char*msg,int mpi_call_result);
无效停工工人(){
printf(“所有工作已完成,正在关闭客户端。\n”);
对于(int i=0;i1004)
printf(“正在将第%d行发送到工作程序%d\n”,currentRow,status.MPI\u SOURCE);
MPI\u发送(¤tRow,1,MPI\u INT,status.MPI\u SOURCE,TAG\u ROW,MPI\u COMM\u WORLD);
罗斯里夫特——;
currentRow++;
}
关闭工人();
免费(数据缓冲);
}
作废doWorkerTasks(){
printf(“工人%d已开始\n”,我的级别);
//将处理后的行作为颜色数组中的第一个元素发送回。
int size=尺寸;
int*数据=(int*)malloc(sizeof(int)*大小);
memset(数据,0,sizeof(大小));
int processingRow=-1;
MPI_状态;
对于(;;){
MPI_Recv(&processingRow,1,MPI_INT,0,MPI_ANY_标记,MPI_COMM_WORLD,&status);
如果(status.MPI_TAG==TAG_FINISHOFF){
printf(“收到完工标签!\n”);
打破
}否则{
//MPI_发送(数据、大小、MPI_INT、0、标记结果、MPI_通信世界);
MPI_发送(&processingRow,1,MPI_INT,0,标记结果,MPI_COMM_WORLD);
}
}
printf(“从属%d已完成工作”,我的等级);
免费(数据);
}
int main(int argc,字符**argv){
如果(argc==2){
sscanf(argv[1]、“%d”和维度);
}否则{
尺寸=1000;
}
作业(argc、argv);
如果(我的军衔==大师军衔){
域主任务(argc、argv);
}否则{
doWorkerTasks();
}
定稿();
}
void quit(const char*msg,int mpi_call_result){
printf(“\n%s\n”,msg);
MPI_中止(MPI_通信世界、MPI_调用结果);
退出(mpi_调用_结果);
}
void finalize(){
mpi_call_result=mpi_Finalize();
如果(mpi调用结果!=0){
退出(“完成MPI系统失败,正在中止…”,MPI\u调用\u结果);
}
}
void doInitWork(int argc,char**argv){
mpi_call_result=mpi_Init(&argc,&argv);
如果(mpi调用结果!=0){
退出(“初始化系统时出错。正在中止…\n”,mpi\u调用\u结果);
}
MPI通信大小(MPI通信世界和np);
MPI通信等级(MPI通信世界和我的通信等级);
}
非常感谢您的帮助

最好的,
克里斯

如果你看一看你的工作任务,你会发现他们发送的数据信息和收到的数据信息一样多;(他们又收到了一封关闭它们的信)

但是您的主代码:

for (int i = 1; i < np; i++) {
    MPI_Send(&currentRow, 1, MPI_INT, i, TAG_ROW, MPI_COMM_WORLD);
    rowsLeft--;
    currentRow++;

}

for (;;) {
    MPI_Recv(dataBuffer, size, MPI_INT, MPI_ANY_SOURCE, TAG_RESULT, MPI_COMM_WORLD, &status);

    if (rowsLeft == 0)
        break;

    MPI_Send(&currentRow, 1, MPI_INT, status.MPI_SOURCE, TAG_ROW, MPI_COMM_WORLD);
    rowsLeft--;
    currentRow++;
}
在这里,您将发送到所有进程,包括进行发送的秩0。原则上,MPI_发送应该死锁,因为它是一个阻塞发送,并且没有匹配的接收已经发布。您可以在之前发布一个非阻塞接收来避免这种情况,但这是不必要的——秩0不需要让自己知道结束。所以只需将循环更改为

    for (int i = 1; i < np; i++)
for(int i=1;i

tl;dr-您的代码死锁,因为主机没有从工作人员接收到足够的消息;由于大多数MPI库都有一个实现细节,它恰好适用于较小的消息大小。

有很多发送/接收调用,但没有错误检查。。也许你应该检查一下firstHad之前是否有过这种情况,但没有结果。为了清楚起见,省略了它。但我会再检查一遍,也许我忽略了什么。哇,回答得好,非常感谢!我来了
void shutdownWorkers() {
    printf("All work has been done, shutting down clients now.\n");
    for (int i = 0; i < np; i++) {
        MPI_Send(0, 0, MPI_INT, i, TAG_FINISHOFF, MPI_COMM_WORLD);
    }
}
    for (int i = 1; i < np; i++)