У меня проблема с MPI_Isend
и MPI_Irecv
. Я работаю над матрицей смежности графа, которая распределяется по строкам. Мы можем предположить, что каждый процессор содержит одну строку. Для каждой пары индексов (i,j)
мне нужно отправить и получить 2 целых числа. По сути, мне нужно получить некоторую другую информацию из других строк, чтобы выполнять вычисления. Я новичок в MPI, и здесь он переходит в бесконечный цикл, я даже не уверен, что это правильный способ использования MPI_Isend
или MPI_Irecv
в цикле for, а также место ожидания ожидания.
В качестве примера предположим, что у нас есть граф с 6 вершинами, поэтому матрица смежности (adjMatrix
) будет матрицей 6*6, у нас также есть матрица 6*2 для некоторой другой информации, и, наконец, мы распределяем данных между 6 процессорами. Следовательно:
|0 20 16 0 6 0 | |0 1|
|20 0 0 19 0 6 | |1 1|
addMatrix=|16 0 0 0 12 0 | M=|2 1|
|0 19 0 0 0 12| |3 1|
|6 0 12 0 0 9 | |0 0|
|0 6 0 12 9 0 | |1 0|
Распределяем матрицы следующим образом:
P0: |0 20 16 0 6 0 | |0 1|
P1: |20 0 0 19 0 6 | |1 1|
P2: |16 0 0 0 12 0 | |2 1|
P3: |0 19 0 0 0 12| |3 1|
P4: |6 0 12 0 0 9 | |0 0|
P5: |0 6 0 12 9 0 | |1 0|
Теперь каждому процессору необходимо обновить свою часть adjMatrix
. Для этого им нужна информация из некоторой части матрицы M
, которая находится в других процессорах. Например, для того, чтобы P0
обновил индекс (0,1)
, равный 20
, необходимо иметь доступ к строке 1
матрицы M
, равной {1,1}
. Следовательно:
P1
должен отправитьMLocal[0][0]=1
иMLocal[0][1]=1
наP0
, в которомP0
получит их какM_j0
иM_j1
соответственно.А также
P0
должен отправитьMLocal[0][0]=0
иMLocal[0][1]=1
наP1
, в которомP1
получит их какM_j0
иM_j1
соответственно.
for(int i=0;i<rows;i++){
for (int j=0; j<n; j++)
{
int M_j0,M_j1;
MPI_Isend(&MLocal[i][0], 1, MPI_INT, j, my_rank+i*n+j+0, MPI_COMM_WORLD, &send_request0);
MPI_Isend(&MLocal[i][1], 1, MPI_INT, j, my_rank+i*n+j+1, MPI_COMM_WORLD, &send_request1);
MPI_Irecv(&M_j0, 1, MPI_INT, j, my_rank+i*n+j+0, MPI_COMM_WORLD, &recv_request0);
MPI_Irecv(&M_j1, 1, MPI_INT, j, my_rank+i*n+j+1, MPI_COMM_WORLD, &recv_request1);
//MPI_Wait(&send_request0, &status);
//MPI_Wait(&send_request1, &status);
MPI_Wait(&recv_request0, &status);
MPI_Wait(&recv_request1, &status);
// Do something ...
}
}
Затем по предложению Gilles Gouaillardet я изменил эти 4 MPI_Isend
и MPI_Irecv
на:
MPI_Sendrecv(&MoatsLocal[i][0], 1, MPI_INT, j, my_rank+i*n+j+0, &M_j0,1, MPI_INT, my_rank, my_rank+i*n+j+0, MPI_COMM_WORLD, &status);
MPI_Sendrecv(&MoatsLocal[i][1], 1, MPI_INT, j, my_rank+i*n+j+1, &M_j1,1, MPI_INT, my_rank, my_rank+i*n+j+1, MPI_COMM_WORLD, &status);
Но тем не менее, он входит в бесконечный цикл.
ОБНОВИТЬ:
Я обновил код, отчасти проблема была из-за ранжирования процессоров и соответствия тегов. Я исправил эту часть, но, тем не менее, она была склонна к взаимоблокировке, и я думаю, что знаю, в чем проблема. А может и не решить. Если бы у меня было достаточное количество процессоров, чтобы распределить каждую строку по процессору, т.е. n=p, то не было бы никаких проблем. Но проблема в том, что если количество процессоров меньше n
, то поток по главной диагонали идет не красиво. Поясняю на примере, допустим у нас 4 процессора и n=6
. Предположим, что это распределение:
P0: |0 20 16 0 6 0 | |0 1|
P1: |20 0 0 19 0 6 | |1 1|
|16 0 0 0 12 0 | |2 1|
P2: |0 19 0 0 0 12| |3 1|
P3: |6 0 12 0 0 9 | |0 0|
|0 6 0 12 9 0 | |1 0|
Это то, что происходит через петлю.
Первая итерация:
P0 отправляет и получает в/из P1 информацию для (0,1):"20" и ждет (готово)
P1 отправляет и получает в/из P0 информацию для (1,0):"20" и ждет (готово)
P2 отправляет и получает в/из P1 информацию для (3,1):"19" и ждет
P3 отправляет и получает в/из P0 информацию для (4,1):"6" и ждет
Вторая итерация:
P0 отправляет и получает в/из P1 информацию для (0,2):"16" и ждет
P1 отправляет и получает на/от P2 информацию для (1,3):"19" и ждет (готово)
P2 ждал P1 (3,1): "19", затем просто получил его и готово!
P3 ожидает P0 для (4,1):"6" и ждет
Третья итерация:
P0 ожидает P1 для (0,2):"16"
P1 отправляет и получает в/из P3 информацию для (1,5):"19" и ждет
P2 отправляет и получает на/от P3 информацию для (3,5):"12" и ждет
P3 ожидает P0 для (4,1):"6"
Четвертая итерация:
P0 ожидает P1 для (0,2):"16"
P1 ожидает P3 для (1,5):"19"
P2 ожидает P3 для (3,5):"12"
P3 ожидает P0 для (4,1):"6"
Сейчас все ждут друг друга, не думаю, что это как-то решить. Решение, предложенное ptb, может сработать, я попробую его.
Тем не менее, любая другая идея приветствуется!
MPI_Waitall(4, ...);
- person Gilles Gouaillardet   schedule 04.04.2018MPI_Sendrecv()
- person Gilles Gouaillardet   schedule 04.04.2018MPI_Waitall(4, ...)
? это должно быть менее подвержено взаимоблокировкам. - person Gilles Gouaillardet   schedule 05.04.2018