mpi 矩阵向量乘法死锁

问题描述 投票:0回答:1

我正在尝试在“使用 MPI”中实现矩阵向量 MPI 程序 便携式并行编程 消息传递接口 第二版 威廉·格罗普 尤因·拉斯克 Anthony Skjellum 的书,第 35 页此处

这是一个自调度程序,其中 0 阶进程将向量广播给所有其他进程,并向每个进程发送一行矩阵。然后,进程计算向量和行之间的点积,并将结果发送回排名 0 的进程。书中的示例是用 Fortran 编写的,我将其移植到 C++ 中,但在第一次发送后就死锁了

#include "mpi.h"
#include <iostream>
#include <vector>

int main(){

    int W_rank, W_size;
    int rows = 9;
    int cols = 9;

    std::vector<double> b(cols);
    std::vector< std::vector<double> > a(rows);
    std::vector<double> c(rows);
    std::vector<double> buffer(cols);

    for(auto& row : a) row.resize(cols);

    MPI_Init(NULL, NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &W_size);
    MPI_Comm_rank(MPI_COMM_WORLD, &W_rank);

    if(W_rank == 0){
        
        std::fill(b.begin(), b.end(), 1);
        
        for(auto& row : a){
            std::fill(row.begin(), row.end(), 1);
        }

        int numsent = 0;
        
        MPI_Bcast(b.data(), b.size(), MPI_DOUBLE, 0, MPI_COMM_WORLD);
        
        for(int i=0; i<W_size; ++i){
            for(int j=0; j<cols; ++j){
                buffer[j] = a[i][j];
            }
            MPI_Send(buffer.data(), buffer.size(), MPI_DOUBLE, i, i, MPI_COMM_WORLD);///////deadlocks here///////////
            ++numsent;
        }

        double ans;
        MPI_Status status;
        for(int i=0; i<rows; ++i){
            MPI_Recv(&ans, 1, MPI_DOUBLE, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
            int sender = status.MPI_SOURCE;
            int tag = status.MPI_TAG;
            c[tag] = ans;
            if(numsent<rows){
                for(int j=0; j<cols; ++j){
                    buffer[j] = a[numsent][j];
                }
                MPI_Send(buffer.data(), buffer.size(), MPI_DOUBLE, sender, numsent, MPI_COMM_WORLD);
                ++numsent;
            }
            else{
                MPI_Send(MPI_BOTTOM, 0, MPI_DOUBLE, sender, -1, MPI_COMM_WORLD);
            }
        }
    }
    else{

        MPI_Bcast(b.data(), b.size(), MPI_DOUBLE, 0, MPI_COMM_WORLD);
        
        MPI_Status status;
        
        while(1){
            MPI_Recv(buffer.data(), buffer.size(), MPI_DOUBLE, 0, MPI_ANY_TAG, MPI_COMM_WORLD, &status);//////deadlocks here///////////////////
            if(status.MPI_TAG == -1) break;
            int row = status.MPI_TAG;
            double ans = 0;
            for(int i=0; i<cols; ++i){
                ans += buffer[i]*b[i];
            }
            MPI_Send(&ans, 1, MPI_DOUBLE, 0, row, MPI_COMM_WORLD);
        }
       
    }
    
    MPI_Finalize();

    return 0;
}
c++ parallel-processing mpi deadlock
1个回答
0
投票

您对 MPI 标签的处理是危险的或错误的。首先,标签必须是非负的,所以你的

-1
标签是非法的。如果在内部它被解释为无符号,它就会变成一个非常大的标签。其次:标签值有上限,因此使用
numsent
作为标签很聪明,但可能会出现问题。我会使用 tag=0 表示常规消息,使用 tag=1 表示终止,或类似的东西。

© www.soinside.com 2019 - 2024. All rights reserved.