2015-06-05 70 views
1

我正在編寫一個程序,其中進程0將圖像的各個部分發送到其他進程,這些進程轉換(長時間操作)這部分並返回到等級0.我遇到問題一件事。爲了重現我的問題,我寫了一個簡單的例子。大小爲512x512px的圖像在過程0中分成4個部分(垂直條紋)。接下來其他過程將此部分保存在磁盤上。問題是每個進程都保存相同的部分。我發現圖像正確地拆分了部分,但問題可能是發送數據。我的代碼有什麼問題?MPI - 將圖像的部分發送到不同的進程

運行:

mpirun -np 5 ./example 

主營:

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

    int size, rank; 
    MPI_Request send_request, rec_request; 
    MPI_Status status; 
    ostringstream s; 

    MPI_Init(&argc, &argv); 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
    MPI_Comm_size(MPI_COMM_WORLD, &size); 
    if (rank == 0) { 

     Mat mat = imread("/home/user/original.jpg", CV_LOAD_IMAGE_COLOR); 
     if (!mat.data) exit(-1); 

     int idx = 1; 
     for (int c = 0; c < 512; c += 128) { 
      Mat slice = mat(Rect(c, 0, 128, 512)).clone(); 
      MPI_Isend(slice.data, 128 * 512 * 3, MPI_BYTE, idx, 0, MPI_COMM_WORLD, &send_request); 
      idx++; 
     } 
    } 
    if (rank != 0) { 
     Mat test = Mat(512, 128, CV_8UC3); 
     MPI_Irecv(test.data, 128 * 512 * 3, MPI_BYTE, 0, 0, MPI_COMM_WORLD, &rec_request); 
     MPI_Wait(&rec_request, &status); 

     s << "/home/user/p" << rank << ".jpg"; 
     imwrite(s.str(), test); 
    } 

    MPI_Finalize(); 
    return 0; 
} 

回答

2

如果你堅持使用非阻塞操作,然後適當的方式在同一時間發出多個它們是:

MPI_Request *send_reqs = new MPI_Request[4]; 

int idx = 1; 
for (int c = 0; c < 512; c += 128) { 
    Mat slice = mat(Rect(c, 0, 128, 512)).clone(); 
    MPI_Isend(slice.data, 128 * 512 * 3, MPI_BYTE, idx, 0, MPI_COMM_WORLD, &send_reqs[idx-1]); 
    idx++; 
} 

MPI_Waitall(4, send_reqs, MPI_STATUSES_IGNORE); 
delete [] send_reqs; 

另一個(恕我直言更好)選擇是利用MPI_Scatterv散射原始數據緩衝區。因此,您甚至可以保存圖像矩陣的克隆部分。

if (rank == 0) { 
    Mat mat = imread("/home/user/original.jpg", CV_LOAD_IMAGE_COLOR); 
    if (!mat.data) exit(-1); 

    int *send_counts = new int[size]; 
    int *displacements = new int[size]; 

    // The following calculations assume row-major storage 
    for (int i = 0; i < size; i++) { 
     send_counts[i] = displacements[i] = 0; 
    } 
    int idx = 1; 
    for (int c = 0; c < 512; c += 128) { 
     displacements[idx] = displacements[idx-1] + send_counts[idx-1]; 
     send_counts[idx] = 128 * 512 * 3; 
     idx++; 
    } 

    MPI_Scatterv(mat.data, send_counts, displacements, MPI_BYTE, 
       NULL, 0, MPI_BYTE, 0, MPI_COMM_WORLD); 

    delete [] send_counts; 
    delete [] displacements; 
} 
if (1 <= rank && rank <= 4) { 
    Mat test = Mat(512, 128, CV_8UC3); 
    MPI_Scatterv(NULL, NULL, NULL, MPI_BYTE, 
       test.data, 128 * 512 * 3, MPI_BYTE, 0, MPI_COMM_WORLD); 

    s << "/home/user/p" << rank << ".jpg"; 
    imwrite(s.str(), test); 
} 

請注意如何準備MPI_Scatterv的參數。由於您只散佈到4個MPI進程,因此將send_counts[]的某些元素設置爲零可讓程序在超過5個MPI進程中正常運行。此外,原始代碼中的根級別不會發送給自己,因此send_counts[0]必須爲零。

1

的問題是,你是不是等到發送操作完成矩陣Mat被破壞之前。使用MPI_Send而不是MPI_Isend

如果您確實想要使用非阻塞通信,則必須跟蹤所有MPI_Request對象和所有Mat圖像,直到發送完成。