Создание MPI - интерфейса для сетевого кластера.
Цель работы: Изучение и разработка интерфейса передачи сообщений для параллельных приложений. Необходимо создать библиотеку функций MPI - интерфейса для кластера на базе сети Novell Netware.
Выполнение работы:
В данной работе используются функции из лабораторной работы №6, повторно их текст не приводится.
Структура данных для коммуникатора, используемого для связи между ветвями приложения.
typedef struct
{
// управляющие блоки для различных операций
NCB reset_ncb;
NCB adapter_status_ncb;
NCB session_status_ncb;
NCB call_ncb;
NCB listen_ncb;
NCB add_name_ncb;
NCB add_group_name_ncb;
NCB delete_name_ncb;
NCB send_ncb;
NCB receive_ncb;
NCB receive_any_ncb;
NCB hangup_ncb;
NCB temp_ncb;
NCB send_datagram_ncb;
NCB receive_datagram_ncb;
NCB send_bcst_datagram_ncb;
NCB receive_bcst_datagram_ncb;
NCB cancel_ncb;
byte pos; // Номер ветви, определяется в процессе инициализации
byte cur; // Номер ветви, с которой устанавливается соединение
byte num; // Номер имени ветви (NetBios)
char name[16]; // Имя ветви (NetBios)
byte progress; // Указание того, что идут вычисления
byte ack; // Количество ответивших серверу ветвей (сбор результатов)
double summary; // результат
long time_sec; // Время начала вычислений, в секундах
short time_mili; // Время начала вычислений, тысячные секунды
} COMM;
COMM MPI_COMM_WORLD – коммуникатор, создаваемый при инициализации ветви
Функции MPI
Данная функция возвращает количество объединенных ветвей, число которых вычисляется путем подсчета количества активных сессий для имени ветви.
int MPI_Comm_size(COMM comm, int *size)
{
STATUS_INFO info;
name_status(comm, comm.name, &info);
int duplicate = 0, i, j;
char name[16], *off;
name_status(MPI_COMM_WORLD, MPI_COMM_WORLD.name, &info);
for (i = 0,j = 0; i < info.session_count; i++) {
if (info.session_data[i].state != 3)
continue;
strcpy(name, info.session_data[i].remote_name);
off = name + 6;
if (atoi(off) == MPI_COMM_WORLD.pos && duplicate) {
continue;
}
j++;
if (atoi(off) == MPI_COMM_WORLD.pos) {
duplicate = 1;
}
}
*size = j - 1;
return 0;
}
Функция возвращает номер ветви, данные получаются из коммуникатора
int MPI_Comm_rank(COMM comm, int *rank)
{
*rank = comm.pos - 1;
return 0;
}
Функция получения сообщения, так как не используется получение сообщений от конкретного имени, то реализована только часть, выполняющая получение данных от любой ветви (MPI_ANY_SOURCE)
int MPI_Recv(void *buf, int count, int source, COMM &comm)
{
if (source == MPI_ANY_SOURCE)
return receive_any(comm, post_handle, buf, count);
else
return -1;
}
Функция передачи сообщения в заданную ветвь
int MPI_Send(void *buf, int count, int dest, COMM &comm)
{
STATUS_INFO info;
byte lsn;
char name[16], temp[16], dest_char[16];
strcpy(temp, "Worker");
itoa(dest, dest_char, 10);
strcat(temp, dest_char);
real_name(name, temp);
name_status(MPI_COMM_WORLD, MPI_COMM_WORLD.name, &info);
for (int i = 0; i < info.session_count; i++) {
if (!strcmp(name,info.session_data[i].remote_name)) {
lsn = info.session_data[i].lsn;
break;
}
}
return send(comm, lsn, buf, count);
}
Функция инициализации MPI. Ветвь последовательно перебирает номера, отыскивая первой свободное, регистрируется с этим именем, устанавливает соединения с собой и переходит в режим listen any, для того, чтобы последующие ветви могли установить с ней соединение. Константа MAX_WORKER определяет максимально возможное количество ветвей и задается на этапе компиляции.
int MPI_Init(int argc,char* argv[])
{
puts("Выполняется функция MPI_Init");
check_netbios();
char name[16], temp[4];
int i;
MPI_COMM_WORLD.progress = 0;
MPI_COMM_WORLD.ack = 0;
for(i = 1; i <= MAX_WORKER; i++) {
strcpy(name, "Worker");
itoa(i, temp, 10);
strcat(name, temp);
if (add_name(MPI_COMM_WORLD, name)) {
continue;
}
else {
printf("Удалось зарегистрироваться под именем %s\n", name);
strcpy(MPI_COMM_WORLD.name, name);
MPI_COMM_WORLD.pos = i;
MPI_COMM_WORLD.cur = 1;
MPI_COMM_WORLD.num =
MPI_COMM_WORLD.add_name_ncb.NCB_NUM;
listen(MPI_COMM_WORLD, "*", name, post_handle, 20, 20);
call(MPI_COMM_WORLD, "Worker1", name, post_handle, 20, 20);
break;
}
}
if (i > MAX_WORKER) {
printf("Лимит участников превышен, завершение MPI_Init.\n");
puts("Нажмите любую клавишу для выхода");
bioskey(0);
exit(1);
}
return 0;
}
Функция завершения работы ветви. Функция kill() разрывает все активные соединения.
int MPI_Finalize()
{
puts("Выполняется функция MPI_Finalize");
cancel(MPI_COMM_WORLD, post_handle, &MPI_COMM_WORLD.receive_any_ncb);
cancel(MPI_COMM_WORLD, post_handle, &MPI_COMM_WORLD.listen_ncb);
kill(MPI_COMM_WORLD);
printf("Удаляю имя %s из таблицы имен\n", strip_name(MPI_COMM_WORLD.name));
delete_name(MPI_COMM_WORLD, MPI_COMM_WORLD.name);
return 0;
}
Тестирование (путем непосредственного использования) данных функций производится в лабораторной работе №8.
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.