MPI_Irecv не получает все посылки?

В этом упрощенном коде я пытаюсь достичь следующего:

  • 2 типа процессов (корень и потомок, идентификаторы / ранг = 10 и 0-9 соответственно)
  • в этом:
    • root будет слушать детей «завершено»
    • дети будут слушать корневое уведомление, когда все закончится
  • пока нет победителя (еще не все сделано):
    • дети будут иметь 20% -ную вероятность, что они будут сделаны (и уведомят корня, что они сделаны)
    • root проверит что все сделано
      • если все сделано: отправьте уведомление детям «победителя»

У меня есть код как:

int numprocs, id, arr[10], winner = -1;
bool stop = false;
MPI_Request reqs[10], winnerNotification;

MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &id);

for (int half = 0; half < 1; half++) {
for (int round = 0; round < 1; round++) {
if (id == 10) { // root
// keeps track of who has "completed"fill_n(arr, 10, -1);
for (int i = 0; i < 10; i++) {
MPI_Irecv(&arr[i], 1, MPI_INT, i, 0, MPI_COMM_WORLD, &reqs[i]);
}
} else if (id < 10) { // children
// listen to root of winner notification/indication to stop
MPI_Irecv(&winner, 1, MPI_INT, 10, 1, MPI_COMM_WORLD, &winnerNotification);
}

while (winner == -1) {
//cout << id << " is in loop" << endl;

if (id < 10 && !stop && ((rand() % 10) + 1) < 3) {
// children has 20% chance to stop (finish work)
MPI_Send(&id, 1, MPI_INT, 10, 0, MPI_COMM_WORLD);
cout << id << " sending to root" << endl;
stop = true;
} else if (id == 10) {
// root checks number of children completed
int numDone = 0;
for (int i = 0; i < 10; i++) {
if (arr[i] >= 0) {
//cout << "root knows that " << i << " has completed" << endl;
numDone++;
}
}
cout << "numDone = " << numDone << endl;

// if all done, send notification to players to stop
if (numDone == 10) {
winner = 1;
for (int i = 0; i < 10; i++) {
MPI_Send(&winner, 1, MPI_INT, i, 1, MPI_COMM_WORLD);
}
cout << "root sent notification of winner" << endl;
}
}
}
}
}

MPI_Finalize();

Выход из отладки coutПохоже: проблема, кажется, корень не получает все детские уведомления, что они завершены?

2 sending to root
3 sending to root
0 sending to root
4 sending to root
1 sending to root
8 sending to root
9 sending to root
numDone = 1
numDone = 1
... // many numDone = 1, but why 1 only?
7 sending to root
...

Я думал, что, возможно, я не могу получить в массив: но я пытался

if (id == 1) {
int x = 60;
MPI_Send(&x, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
} else if (id == 0) {
MPI_Recv(&arr[1], 1, MPI_INT, 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
cout << id << " recieved " << arr[1] << endl;
}

Который работает.

ОБНОВИТЬ

Кажется, это решается, если я добавлю MPI_Barrier(MPI_COMM_WORLD) до конца цикла while, но почему? Даже если процессы не синхронизируются, в конце концов, дети отправят root, что они завершили, и root должен «прослушать» это и обработать соответственно? Кажется, что происходит, когда root продолжает работать, загружая все ресурсы для выполнения детьми вообще? Или что здесь происходит?

ОБНОВЛЕНИЕ 2: некоторые дети не получают уведомления от root

Хорошо, теперь проблема в том, что root не получает уведомления детей о том, что они завершили ответ @ MichaelSh, я сосредотачиваюсь на детях, не получающих от родителей. Вот код, который воспроизводит эту проблему:

int numprocs, id, arr[10], winner = -1;
bool stop = false;
MPI_Request reqs[10], winnerNotification;

MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &id);

srand(time(NULL) + id);

if (id < 10) {
MPI_Irecv(&winner, 1, MPI_INT, 10, 0, MPI_COMM_WORLD, &winnerNotification);
}
MPI_Barrier(MPI_COMM_WORLD);

while (winner == -1) {
cout << id << " is in loop ..." << endl;
if (id == 10) {
if (((rand() % 10) + 1) < 2) {
winner = 2;
for (int i = 0; i < 10; i++) {
MPI_Send(&winner, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
}
cout << "winner notifications sent" << endl;
}
}
}

cout << id << " b4 MPI_Finalize. winner is " << winner << endl;

MPI_Finalize();

Вывод выглядит так:

# 1 run
winner notifications sent
10 b4 MPI_Finalize. winner is 2
9 b4 MPI_Finalize. winner is 2
0 b4 MPI_Finalize. winner is 2

# another run
winner notifications sent
10 b4 MPI_Finalize. winner is 2
8 b4 MPI_Finalize. winner is 2

Заметьте, что некоторые процессы не получают уведомления от родителя? Это почему, MPI_Wait для дочерних процессов их просто повесят? Так как мне решить это?

Также

Все MPI_Barrier делает в вашем случае — он ждет, пока ответ ребенка завершится. Пожалуйста, проверьте мой ответ для лучшего решения

Если я этого не сделаю, я полагаю, что каждый ответ ребенка займет всего несколько мс? Таким образом, даже если я не буду ждать / барьер, я ожидал бы, что получение все еще произойдет вскоре после отправки? Разве процессы заканчивают тем, что перебивают ресурсы, а другие процессы не запускаются?

3

Решение

Пожалуйста, попробуйте этот блок кода (проверка ошибок для простоты опущена):

...
// root checks number of children completed
int numDone = 0;
MPI_Status statuses[10];
MPI_Waitall(10, reqs, statuses);
for (int i = 0; i < 10; i++) {
...

редактировать Лучшее решение:
Каждый дочерний элемент инициирует получение уведомления от корневого победителя и отправляет свое уведомление корневому пользователю.
Root инициирует получение уведомления о победителе в массив и переходит в ожидание получения всех уведомлений, а затем отправляет идентификатор победителя дочерним элементам.
Вставьте этот код ниже после for (int round = 0; round < 1; round++)

            if (id == 10)
{ // root
// keeps track of who has "completed"memset(arr, -1, sizeof(arr));
for (int i = 0; i < 10; i++)
{
MPI_Irecv(&arr[i], 1, MPI_INT, i, 0, MPI_COMM_WORLD, &reqs[i]);
}
}
else if (id < 10)
{ // children
// listen to root of winner notification/indication to stop
MPI_Irecv(&winner, 1, MPI_INT, 10, 1, MPI_COMM_WORLD, &winnerNotification);
}

if (id < 10)
{
while(((rand() % 10) + 1) < 3) ;

// children has 20% chance to stop (finish work)
MPI_Send(&id, 1, MPI_INT, 10, 0, MPI_COMM_WORLD);
std::cout << id << " sending to root" << std::endl;
// receive winner notification
MPI_Status status;
MPI_Wait(&winnerNotification, &status);
// Process winner notification
}
else if (id == 10)
{
MPI_Status statuses[10];
MPI_Waitall(10, reqs, statuses);

// if all done, send notification to players to stop
{
winner = 1;
for (int i = 0; i < 10; i++)
{
MPI_Send(&winner, 1, MPI_INT, i, 1, MPI_COMM_WORLD);
}
std::cout << "root sent notification of winner" << std::endl;
}
}
2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]