2017-07-14 53 views
0

我需要還原節點從其他節點獲取元素列表(存儲在向量中)的副本。我定義了我自己的減少功能,但它不起作用。該程序終止/崩潰。傳遞並推入MPI_Reduce中的向量

這是代碼:

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

using namespace std; 

void pushTheElem(vector<int>* in, vector<int>* inout, int *len, MPI_Datatype *datatype) 
{ 
    vector<int>::iterator it; 
    for (it = in->begin(); it < in->end(); it++) 
    { 
     inout->push_back(*it); 
    } 
} 

int main(int argc, char **argv) 
{ 
    int numOfProc, procID; 
    vector<int> vect, finalVect; 

    MPI_Init(&argc, &argv); 
    MPI_Comm_size(MPI_COMM_WORLD, &numOfProc); 
    MPI_Comm_rank(MPI_COMM_WORLD, &procID); 

    MPI_Op myOp; 
    MPI_Op_create((MPI_User_function*)pushTheElem, true, &myOp); 

    for (int i = 0; i < 5; i++) 
    { 
     vect.push_back(procID); 
    } 

    MPI_Reduce(&vect, &finalVect, 5, MPI_INT, myOp, 0, MPI_COMM_WORLD); 

    if (procID == 0) 
    { 
     vector<int>::iterator it; 
     cout << "Final vector elements: " << endl; 

     for (it = finalVect.begin(); it < finalVect.end(); it++) 
      cout << *it << endl; 
    } 

    MPI_Finalize(); 
    return 0; 
} 
+0

請提供有關崩潰的一些細節。至少應該有某種異常發生......程序的輸出是什麼? –

+0

這就是我得到的:工作中止:[等級]消息。沒有調用finalize,退出[0]進程。 [1]終止。 ----錯誤分析----- testMPI.exe過早結束並可能崩潰。退出代碼0xc0000005。 – Jack

+0

當我用2個進程運行程序時,我知道了。 – Jack

回答

3

看來你要收集所有進程的所有元素。這是不是還原,它是一個收集操作。的減少結合了相同長度的多個陣列此特定長度的數組:

MPI_Reduce

這不是的情況下,組合兩個數組時產生長度等於輸入數組的總和的陣列。使用MPI,您不能簡單地使用指針來操作,就像您在縮減操作中所做的那樣。由於進程具有單獨的地址空間,因此無法向MPI發送指針。 MPI接口確實使用指針,但只使用包含已知類型和已知大小的數據區域。

您可以通過MPI_Gather輕鬆完成您的任務。

MPI_Gather

// vect.size() must be the same on every process, otherwise use MPI_Gatherv 
// finalVect is only needed on the root. 
if (procID == 0) finalVect.resize(numOfProc * vect.size()); 
MPI_Gather(vect.data(), 5, MPI_INT, finalVect.data(), 5, MPI_INT, 0, MPI_COMM_WORLD); 
+0

非常感謝,這正是我所需要的。 – Jack

1

我不認爲你可以通過使用MPI這樣的載體。 MPI執行什麼操作需要第一個指針,並將其解釋爲INT類型的數據塊,並且定義了長度。請考慮矢量如何實現。向量本身就是一個小的控制結構,指向堆上的某個數組。所以傳遞vector *不是提供指向數據的指針,而是指向這個控制結構,當你的程序嘗試使用它作爲向量時,這會導致未定義的行爲。

您需要使用MPI對原始數據進行操作。試試這個(沒有測試過,因爲我手頭沒有MPI):

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

using namespace std; 

void pushTheElem(int* in, int* inout, int *len, MPI_Datatype *datatype) 
{ 
    for(inti=0;i<*len;++i){ 
     inout[i]=in[i]; 
    } 
} 

int main(int argc, char **argv) 
{ 
    int numOfProc, procID; 
    vector<int> vect, finalVect; 

    MPI_Init(&argc, &argv); 
    MPI_Comm_size(MPI_COMM_WORLD, &numOfProc); 
    MPI_Comm_rank(MPI_COMM_WORLD, &procID); 

    MPI_Op myOp; 
    MPI_Op_create((MPI_User_function*)pushTheElem, true, &myOp); 

    for (int i = 0; i < 5; i++) 
    { 
     vect.push_back(procID); 
    } 
    finalVect.resize(vect.size()); 
    MPI_Reduce(vect.data(), finalVect.data(), 5, MPI_INT, myOp, 0, MPI_COMM_WORLD); 

    if (procID == 0) 
    { 
     vector<int>::iterator it; 
     cout << "Final vector elements: " << endl; 

     for (it = finalVect.begin(); it < finalVect.end(); it++) 
      cout << *it << endl; 
    } 

    MPI_Finalize(); 
    return 0; 
} 
+0

非常感謝,現在我明白它是如何工作的。該代碼不會產生任何錯誤。唯一的是finalVect將始終只有從上次處理過程中獲得的元素。 pushTheElem中的循環會覆蓋finalVect中已有的任何內容。 – Jack

+0

@Jack預期的行爲是什麼?如果使用2個MPI任務運行,您能指定finalVect中的期望嗎? –

+0

我基本上希望輸出包含從兩個進程收集的元素。 @Zulan向我澄清說,我應該使用的是MPI_Gather,它給了我正確的輸出。謝謝。 – Jack