/* * ex1.c -- пример 1 см.также -- http://www.csa.ru/~il/mpi_tutor * * Простейшая приемопередача: * MPI_Send, MPI_Recv * Завершение по ошибке: * MPI_Abort */ #include #include /* Идентификаторы сообщений */ #define tagFloatData 1 #define tagDoubleData 2 /* Этот макрос введен для удобства, */ /* он позволяет указывать длину массива в количестве ячеек */ #define ELEMS(x) ( sizeof(x) / sizeof(x[0]) ) int main( int argc, char **argv ) { int size, rank, count; float floatData[10]; double doubleData[20]; MPI_Status status; /* Инициализируем библиотеку */ MPI_Init( &argc, &argv ); /* Узнаем количество задач в запущенном приложении */ MPI_Comm_size( MPI_COMM_WORLD, &size ); /* ... и свой собственный номер: от 0 до (size-1) */ MPI_Comm_rank( MPI_COMM_WORLD, &rank ); /* пользователь должен запустить ровно две задачи, иначе ошибка */ if( size != 2 ) { /* задача с номером 0 сообщает пользователю об ошибке */ if( rank==0 ) printf("Error: two processes required instead of %d, abort\n", size ); /* Все задачи-абоненты области связи MPI_COMM_WORLD * будут стоять, пока задача 0 не выведет сообщение. */ MPI_Barrier( MPI_COMM_WORLD ); /* Без точки синхронизации может оказаться, что одна из задач * вызовет MPI_Abort раньше, чем успеет отработать printf() * в задаче 0, MPI_Abort немедленно принудительно завершит * все задачи и сообщение выведено не будет */ /* все задачи аварийно завершают работу */ MPI_Abort( MPI_COMM_WORLD, /* Описатель области связи, на которую */ /* распространяется действие ошибки */ MPI_ERR_OTHER ); /* Целочисленный код ошибки */ return -1; } if( rank==0 ) { /* Задача 0 что-то такое передает задаче 1 */ MPI_Send( floatData, /* 1) адрес передаваемого массива */ 5, /* 2) сколько: 5 ячеек, т.е. floatData[0]..floatData[4] */ MPI_FLOAT, /* 3) тип ячеек */ 1, /* 4) кому: задаче 1 */ tagFloatData, /* 5) идентификатор сообщения */ MPI_COMM_WORLD ); /* 6) описатель области связи, через которую */ /* происходит передача */ /* и еще одна передача: данные другого типа */ MPI_Send( doubleData, 6, MPI_DOUBLE, 1, tagDoubleData, MPI_COMM_WORLD ); } else { /* Задача 1 что-то такое принимает от задачи 0 */ /* дожидаемся сообщения и помещаем пришедшие данные в буфер */ MPI_Recv( doubleData, /* 1) адрес массива, куда складывать принятое */ ELEMS( doubleData ), /* 2) фактическая длина приемного */ /* массива в числе ячеек */ MPI_DOUBLE, /* 3) сообщаем MPI, что пришедшее сообщение */ /* состоит из чисел типа 'double' */ 0, /* 4) от кого: от задачи 0 */ tagDoubleData, /* 5) ожидаем сообщение с таким идентификатором */ MPI_COMM_WORLD, /* 6) описатель области связи, через которую */ /* ожидается приход сообщения */ &status ); /* 7) сюда будет записан статус завершения приема */ /* Вычисляем фактически принятое количество данных */ MPI_Get_count( &status, /* статус завершения */ MPI_DOUBLE, /* сообщаем MPI, что пришедшее сообщение */ /* состоит из чисел типа 'double' */ &count ); /* сюда будет записан результат */ /* Выводим фактическую длину принятого на экран */ printf("Received %d elems\n", count ); /* Аналогично принимаем сообщение с данными типа float * Обратите внимание: задача-приемник имеет возможность * принимать сообщения не в том порядке, в котором они * отправлялись, если эти сообщения имеют разные идентификаторы */ MPI_Recv( floatData, ELEMS( floatData ), MPI_FLOAT, 0, tagFloatData, MPI_COMM_WORLD, &status ); MPI_Get_count( &status, MPI_FLOAT, &count ); } /* Обе задачи завершают выполнение */ MPI_Finalize(); return 0; }