2016-06-20 37 views
1

使用C++和OpenMPI我想創建一個向量,然後在主進程中將向量的部分均勻分配給要處理的從進程。因此,如果矢量有100個整數,並且有5個從屬進程,則每個從屬進程將被髮送20個整數的向量。將向量的一部分分配給從進程

下面是我正在嘗試的代碼,但它不工作。

#include <iostream> 
#include <list> 
#include "mpi.h" 
#include <stdio.h> 
#include <stdlib.h> 
#include <vector> 
#include <algorithm> 
#include <map> 
#include <random> 

using namespace std; 

int main(int argc, char **argv) 
{ 
int rank, size, tag, rc, i; 
MPI_Status status; 
vector<int> vec(100); 
vector<int> split_vec; 

rc = MPI_Init(&argc, &argv); 
rc = MPI_Comm_size(MPI_COMM_WORLD, &size); 
rc = MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
tag=7; 

random_device rd; 
mt19937 gen(rd()); 
uniform_int_distribution<> dis; 
generate(vec.begin(), vec.end(), [&](){ return dis(gen); }); 
// 100 ints/5 slave processes 
int split_size = vec.size()/size; 
// split_size = size of vector of ints that each slave process should get 
int offset = 0; 
int j = 0; 
int max = split_size; 
if (rank==0) { 
// master process 
    for (int i=1; i<size; ++i){ 
      split_vec.clear(); 
      while(j < max){ 
       int elements = i_j + offset; 
       split_vec.push_back(vec[elements]); 
       j++; 
      } 
      max = max + split_size; 
      offset = offset + split_size; 
    MPI_Send(&split_vec[0], split_vec.size(), MPI_INT, i, tag, MPI_COMM_WORLD); 
else{ 
    // slaves processes 
    MPI_Recv(&split_vec[0], split_vec.size(), MPI_INT, 0, tag, MPI_COMM_WORLD, &status); 
    // process the vector 
} 
    MPI_Finalize(); 
}// main 

當我運行上面的代碼我收到以下錯誤:

[comp-01:7562] *** An error occurred in MPI_Recv 
[comp-01:7562] *** on communicator MPI_COMM_WORLD 
[comp-01:7562] *** MPI_ERR_TRUNCATE: message truncated 
[comp-01:7562] *** MPI_ERRORS_ARE_FATAL: your MPI job will now abort 

這似乎是工作它的方式通過vector<int> vec(100)矢量得當,抓住了前二十整數,未來二十年,等但我認爲這是崩潰,因爲我一直覆蓋split_vec中的元素,車庫值正在使其崩潰。當我打印矢量時,因爲我發送它是在它崩潰之前打印的。

0 64 0 33 0 1819240283 808662067 976302125 892679984 2121015 0 49 0 -773125744 32554 0 0 -773125760 32554 0 0 

即使有在vec矢量沒有0或負數。所以我試圖通過添加split_vec.clear();代碼來解決這個問題,但這似乎並不奏效。

下面是我用來編譯和運行它。需要

mpic++ -std=c++11 prog.cpp -o prog.o 
mpirun -np 6 prog.o // 5 slave process 

回答

1

以下更改,使MPI_Recv()成功:

  • 在您發佈的代碼,split_vec.size()是0 MPI_Recv()因爲split_vec不填充呢。因此,MPI_Recv()將收到一條消息,但該向量不會被修改。

  • 必須先分配接收緩衝區。在當前情況下,這意味着必須在致電MPI_Recv(&split_vec[0],MPI_INT,split_size,...);之前添加split_vec.reserve(split_size);。事實上,方法vector::reserve(size_type n)將會增加矢量到至少n元素的容量。正如@Zulan所注意到的那樣,使用split_vec.resize(split_size);更正確,因爲它也更新了向量的大小。

最後,下面的代碼做的伎倆:

split_vec.resize(split_size); 
MPI_Recv(&split_vec[0],MPI_INT,split_vec.size(),...); 

這裏是一個糾正代碼。請注意,用於填充0級數組的索引必須進行修改。通過mpiCC main.cpp -o main -std=c++11 -Wall

#include <iostream> 
#include <list> 
#include "mpi.h" 
#include <stdio.h> 
#include <stdlib.h> 
#include <vector> 
#include <algorithm> 
#include <map> 
#include <random> 

using namespace std; 

int main(int argc, char **argv) 
{ 
    int rank, size, tag; 
    MPI_Status status; 
    vector<int> vec(100); 
    vector<int> split_vec; 

    MPI_Init(&argc, &argv); 
    MPI_Comm_size(MPI_COMM_WORLD, &size); 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
    tag=7; 

    random_device rd; 
    mt19937 gen(rd()); 
    uniform_int_distribution<> dis; 
    generate(vec.begin(), vec.end(), [&](){ return dis(gen); }); 
    // 100 ints/5 slave processes 
    int split_size = vec.size()/size; 
    // split_size = size of vector of ints that each slave process should get 
    int offset = 0; 
    if (rank==0) { 
     // master process 
     for (int i=1; i<size; ++i){ 
      split_vec.clear(); 
      split_vec.reserve(split_size); 
      int j=0; // added j=0 
      while(j < split_size){ 
       int elements = j + offset; 
       split_vec.push_back(vec[elements]); 
       j++; 
      } 
      //max = split_size; 
      offset = offset + split_size; 
      MPI_Send(&split_vec[0], split_vec.size(), MPI_INT, i, tag, MPI_COMM_WORLD); 
     } 
    } 
    else{ 
     // slaves processes 
     split_vec.resize(split_size); 
     MPI_Recv(&split_vec[0], split_vec.size(), MPI_INT, 0, tag, MPI_COMM_WORLD, &status); // until receive is complete, split_vec.size()==0 
    } 
    MPI_Finalize(); 
}// main 

最後編譯它,你要享受功能MPI_Scatter()它究竟想要做什麼!

#include <iostream> 
#include <list> 
#include "mpi.h" 
#include <stdio.h> 
#include <stdlib.h> 
#include <vector> 
#include <algorithm> 
#include <map> 
#include <random> 

using namespace std; 

int main(int argc, char **argv) 
{ 
    int rank, size; 

    vector<int> vec(100); 
    vector<int> split_vec; 

    MPI_Init(&argc, &argv); 
    MPI_Comm_size(MPI_COMM_WORLD, &size); 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 

    random_device rd; 
    mt19937 gen(rd()); 
    uniform_int_distribution<> dis; 
    generate(vec.begin(), vec.end(), [&](){ return dis(gen); }); 
    // 100 ints/5 slave processes 
    int split_size = vec.size()/size; 
    // split_size = size of vector of ints that each slave process should get 


    split_vec.resize(split_size); 
    MPI_Scatter(&vec[0],split_size,MPI_INT,&split_vec[0],split_size,MPI_INT,0,MPI_COMM_WORLD); 

    MPI_Finalize(); 
}// main 
+1

你不能在這裏使用'std :: vector :: reserve'!雖然這不會崩潰,但在MPI_Recv' /'MPI_Scatter'調用之後,vector的大小仍爲0!改用'resize'。 – Zulan

+1

「發送的項目數量必須與要接收的項目數量相匹配」這是不正確的。標準(3.2。4)只要求:「接收消息的長度必須小於或等於接收緩衝區的長度。」 – Zulan

+0

@Zulan:謝謝你在我的回答中發現了這些錯誤!我仍然有很多東西需要了解MPI ... – francis