Реализация топологии Кольцо с MPI

Помечено: ,

В этой теме 0 ответов, 1 участник, последнее обновление  Васильев Владимир Сергеевич 1 неделя, 2 дн. назад.

  • Автор
    Сообщения
  • #5467
    @admin

    Реализуем топологию «кольцо», в которой каждый процесс сгенерирует свой случайный массив целых чисел и отправит его следующему по рангу. В свою очередь нулевой процесс должен получить сообщение от size-1 процесса. Размер массива приходит аргументом командной строки.

    #include <cstdlib>
    #include <iostream>
    #include <ctime>
     
    #include "mpi.h"
     
    #define TOP_RAND 101
     
    using namespace std;
     
    void randomizeIntArray(int* array, int size) {
        for(int i = 0; i < size; i++) {
            array[i] = rand() % TOP_RAND;
        }
     
        return;
    }
     
    void shiftMsg(int rank, int size, int arraySize) {
        int *arr = (int*)malloc(sizeof(int) * arraySize);
        int *res = (int*)malloc(sizeof(int) * arraySize);
     
        randomizeIntArray(arr, arraySize);
     
        MPI_Request request;
        MPI_Isend(arr, arraySize, MPI_INT, (rank+1) % size, 0, MPI_COMM_WORLD, &request);
     
        cout << "process: " << rank << " sent array: ";
        for(int i = 0; i < arraySize; i++) {
            cout << arr[i] << " ";
        }
        cout << endl;
     
        MPI_Irecv(res, arraySize, MPI_INT, (rank-1 + size) % size, 0, MPI_COMM_WORLD, &request);
     
        MPI_Status status;
        //Проверяем, получил ли процесс сообщение 
        if(MPI_Wait(&request, &status) == MPI_SUCCESS) {
            cout << "process: " << rank << " recv array: ";
            for(int i = 0; i < arraySize; i++) {
                cout << res[i] << " ";
            }
            cout << endl;
        }
     
        free(arr);
        free(res);
     
        return;
    }
     
    int main(int argc, char** argv) {
        if(argc != 2) {
            printf("Needs arg: array size\n");
            return 0;
        }
        int rank;
        int size;
     
        int arraySize;
        arraySize = atoi(argv[1]);
     
        MPI_Init(&argc, &argv);
     
        MPI_Comm_size(MPI_COMM_WORLD, &size);
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
     
        //Самый простой способ задания уникального сида для каждого процесса
        srand(time(NULL) + rank);
     
        if(rank == 0) {
            cout << "Shift func: " << endl;
        }
        shiftMsg(rank, size, arraySize);
     
        MPI_Finalize();
        return 0;
    }

    О том, как запустить этот пример читайте тут: Подключение MPI в Visual Studio или Установка MPI на Linux.

    В функции main в этом примере выполняется только инициализация MPI и получение входных данных (размера массива) из параметров командной строки:
    arraySize = atoi(argv[1]);

    После этого каждый процесс, включая root вызывает функцию shiftMsg.

    В этой функции каждый процесс генерирует случайным образом массив и передает его следующему узлу (ведь нам нужна топология «Кольцо», где каждый узел связан со следующим и предыдущим):

    MPI_Isend(arr, arraySize, MPI_INT, (rank+1) % size, 0, MPI_COMM_WORLD, &request);

    Тут size — количество процессов. Последний передаст данные нулевому.

    Затем выполняется получение данных от предыдущего узла:
    MPI_Irecv(res, arraySize, MPI_INT, (rank-1 + size) % size, 0, MPI_COMM_WORLD, &request);

    Так как используется неблокирующая операция, то для проверки завершенности операции вызывается MPI_Wait, который уже является блокирующим.

    if(MPI_Wait(&request, &status) == MPI_SUCCESS) {

    Зачем этот пример? — с одной стороны он неплохо демонстрирует работу с MPI, с ним можно «поиграться», с другой — топология «кольцо» реально применяется. Прочитать про задачи где это будет не просто полезно, но наиболее эффективно можно тут: Миллер, Р. Последовательные и параллельные алгоритмы: Общий подход

Для ответа в этой теме необходимо авторизоваться.