UNIVERSIDADE FEDERAL DO R IO G RANDE DO S UL INSTITUTO DE INFORMÁTICA PROGRAMA DE PÓS -GRADUAÇÃO EM CIÊNCIA DA COMPUTAÇÃO INTRODUÇÃO AO PROCESSAMENTO PARALELO E DISTRIBUÍDO PROF

. NAVAUX

Algoritmo para resolução do problema do Caixeiro Viajante

por Alexandre Cervieri Mônica Py

Porto Alegre, Julho de 2000.

Sumário
1. Introdução ________________________________________________________________ 3 2. Modelagem Inicial __________________________________________________________ 4 3. Implementação distribuída com troca de mensagens _______________________________ 6 4. Medida de Desempenho ______________________________________________________ 8 5. Dificuldades & Comentários __________________________________________________ 9 6. Referências Bibliográficas___________________________________________________ 10 7. Anexo ___________________________________________________________________ 10

2

dado um conjunto de n cidades e uma matriz de distâncias distancias[1. C e C++. com 64 M de memória RAM e clock de 200Mhz.2.1.1. com kernel 2. existe um único processo que pode ser rodado em várias máquinas (chamadas de nodos) já previamente montadas na “máquina virtual” e não modificável em tempo de execução. tem aproximadamente 125 funções para programação e ferramentas para analisar o desempenho. MPI é uma biblioteca de troca de mensagens desenvolvida para ambientes de memória distribuída. 3 . formando uma plataforma de execução de aplicações paralelas de alto desempenho. Se caracteriza por. Introdução O Problema do Caixeiro Viajante é um dos mais clássicos problemas de Complexidade. Esse problema é NP-completo pois não tem solução determinística polinomial.n]. O problema do caixeiro viajante é considerado um problema do otimização. fazer com que seja encontrado um caminho que tenha a menor distância a ser percorrida para que sejam visitadas todas as cidades passando exatamente uma única vez em cada cidade e retornando a cidade de origem. O Grupo de Processamento Paralelo e Distribuído da UFRGS possui uma plataforma de execução para aplicações paralelas um cluster formado por 4 nodos. A semântica da interface MPI foi escrita para ser independente da linguagem. Estes nodos estão interconectados por duas redes de comunicação: uma rede Fast Ethernet e outra rede Myrinet. Esforça-se para definir uma interface de troca de mensagens que seja possível de ser implementada eficientemente.1 e compilador C++ (gcc). Para solucionar o problema do Caixeiro Viajante. MPI define um conjunto de rotinas para facilitar a comunicação (troca de dados e sincronização) entre processos paralelos. máquinas paralelas massivas. no cluster da sala 207 do Instituto de Informática da UFRGS. foi utilizada a biblioteca para programação distribuída MPI.. Uma característica marcante do MPI é que não existem processos.n. além de exibir uma solução é requerida uma certa qualidade ótima da solução. Cluster é uma máquina de alto desempenho que possui uma arquitetura baseada na reunião de um conjunto de estações de trabalho independentes. Cada nodo é um Dual Pentium Pro. NOWs (network of workstations) e redes heterogêneas. interconectadas por uma rede de comunicação. A biblioteca MPI é portável para qualquer arquitetura.. O sistema operacional é Linux. Alguns dos principais objetivos do MPI: • • • Confiabilidade e facilidade de uso são os objetivos principais do MPI. A biblioteca MPI permite que os programas possam ser escritos nas linguagens Fortran.

54 2 76 79 3 46 1 38 4 0 54 79 38 54 0 46 76 79 46 0 71 38 76 71 0 71 Matriz representando o cenário de ligação entre cidades mostrado ao lado. dessa forma.Todo paralelismo é explícito. O terceiro capítulo é descrito como é feita a implementação distribuída com troca de mensagens. Na seção seguinte mostra-se medidas de desempenho do algoritmo sequencial comparado a implementação feita em MPI. caso a sua distância seja realmente menor. ou seja. 4 . Assim que novos caminhos completos são encontrados. Na figura 1 se vê um exemplo de uma configuração com 4 cidades e a matriz gerada. Nos capítulos cinco e seis são feitos comentários do trabalho. Neste caso. até que seja encontrado um caminho que passe por todas as cidades do problema. Essas tarefas são processadas pelos trabalhadores de modo que seja acrescentada mais uma cidade. “Replicated Workers with a Bag of Tasks”. o número de cidades e o conjunto de distâncias que separam cada cidade. Uma primeira implementação do algoritmo descrito acima foi feita na linguagem Java com a utilização de memória compartilhada e threads para o paralelismo dos trabalhadores. Cada tarefa consiste em um caminho parcial das cidades contidas na matriz original. No segundo capítulo apresenta-se a modelagem inicial do algoritmo utilizado. Modelagem Inicial O algoritmo utilizado. esse caminho sempre será ignorado pelo algoritmo. Quando o primeiro caminho é encontrado. e as conclusões. Os dados iniciais necessários para o algoritmo são o número de trabalhadores. respectivamente. É possível representar um cenário onde as cidades não sejam totalmente conectadas indicando a distância entre elas como um valor extremamente alto para sua distância. ele é designado como mínimo. eles substituem o primeiro como o caminho mínimo. as cidades são supostamente totalmente conectadas. juntamente com o código fonte desenvolvido. 2. o programador é responsável por identificar o paralelismo e implementar o algoritmo utilizando chamadas aos comandos da biblioteca MPI. se baseia em um conjunto de trabalhadores que buscam tarefas em uma sacola compartilhada.

Como essa instância é acessível por todos os processos trabalhadores ela exige um controle de sincronismo. Cada tarefa consiste no número de cidades visitadas. • classe Shared: é a classe responsável pela obtenção dos dados iniciais do problema (número de cidades e matriz de distâncias) bem como pelo armazenamento desses dados. inserir novas tarefas na sacola. e pode te quantas instâncias quanto o usuário que dispara o programa desejar. obter tarefas para serem processadas. primitiva da linguagem Java que garante a execução do método como uma sessão crítica.Cada trabalhador foi implementado como uma thread com fluxo próprio de execução. pelo conjunto de cidades deste caminho e pela distância percorrida. Esta implementação está baseada em 3 classes básicas: • classe Task: representa uma tarefa que irá ser processada por um dos trabalhadores. As setas indicam a invocação de um método na outra classe. uma classe adicional. representando o programa princ ipal é a responsável pelo disparo das instâncias das classes Shared. Na figura 2 pode ser visto um diagrama com a representação da comunicação entre cada classe. tendo acesso a um conjunto de dados compartilhados representado por uma instância de uma classe Java. e finalmente atualizar o caminho mínimo quando a distância encontrada for menor. 5 . Os métodos de acesso aos dados compartilhados foram definidos como synchronized. Além das classes acima descritas. A condição de parada dos trabalhadores é não existir mais nenhuma tarefa a ser processada bem como não existir mais nenhum trabalhador processando outra tarefa. é a responsável pelo processamento das tarefas. Cada trabalhador tem acesso a instância dessa classe de modo a poder obter a distância entre duas cidades específicas. • classe Worker: classe derivada da classe Thread. Worker.

Implementação distribuída com troca de mensagens A passagem de uma implementação com memória compartilhada para um modelo distribuído com comunicação feita através de troca de mensagens implica em um esquema de sincronismo e passagem de dados mais complexo. O número de mensagens também é alto. 6 .SalesMan instanciação instanciação RecvTask Shared Worker SendTask Update getDistancia Final Bag : Task 3.

estabeleceu-se um protocolo de troca de mensagens entre os processos.Shared Entrada de dados distâncias Workers SEND distâncias Distribui distâncias Recebe distâncias SENDRECV recvtask Recebe comandos SEND notask SEND task SEND task SEND update SEND stop SEND nowork SEND work Processamento Resultad o Na figura acima pode ser visto um diagrama contendo o fluxo de troca de mensagens entre os processos. onde. De modo a simular o comportamento das classes acima descrito. a classe que anteriormente era 7 .

primeiramente foi executado a versão sequencial do programa. com uso da biblioteca (middleware) de troca de mensagens MPI. e consequentemente a versão paralela. Os resultados obtidos estão considerados nas tabelas. (isso em ambiente Linux. com resultado 261 unidades. a solução do algoritmo em JAVA. Medida de Desempenho Para realizar os testes. Na realização dos testes. Contatamos que para 10 cidades.compartilhada passou a ser representada por um objeto servidor que se tornou o centro de comunicação para os demais processos. sendo o caminho encontrado 0 1 6 2 7 4 5 8 9 3. tempo necessário para a execução do programa sequencial e o tempo de execução em paralelo. Cada arquivo desenvolvido contém os valores apresentados no texto a seguir. Segue as tabelas com as matrizes e os resultados obtidos em cada execução. obteve tempo de processamento 12826619 ms que equivale a 3h33m46s. Em cada tabela encontra-se o número de cidades. 4. pois em Windows NT a Máquina JAVA não suportou a carga).txt Matriz de distâncias 0 77 12 70 77 0 49 57 12 49 0 1 70 57 1 0 Número de Cidades 4 Matriz Cidades Tempo Seqüencial (ms) 930 Tabela 1 Tempo Paralelo (s) 0s 8 . O número de cidades inicialmente testadas foram 4. foi criado arquivos contendo matrizes de distancias para as cidades. Arquivo: distancias_4. A programação foi feita utilizando-se ANSI C.

Arquivo: distancias_5. 9 .txt Matriz de distâncias 0 2 40 4 96 46 2 0 56 92 82 19 40 56 0 47 48 95 4 92 47 0 73 0 96 82 48 73 0 33 46 19 95 0 33 0 Número de Cidades 6 Matriz Cidades Tempo Seqüencial (s) 2s42 Tabela 3 Tempo Paralelo (s) 0.4s 5. Dificuldades & Comentários O trabalho desenvolvido incentiva a utilização de arquiteturas paralelas e distribuídas para a resolução de aplicações que necessitam de grande capacidade de processamento.txt Matriz de distâncias 0 21 61 80 3 21 0 4 71 7 61 4 0 97 60 80 71 97 0 57 3 7 60 57 0 Número de Cidades 5 Matriz Cidades Tempo Seqüencial (s) 1s21 Tabela 2 Tempo Paralelo (s) 0. Assim conclui-se que os resultados de desempenho alcançados compensam o trabalho de adaptar o código seqüencial para paralelo. Em anexo encontra-se o código fonte do trabalho.2s Arquivo: distancias_6.

h salesman. San Francisco: Morgan Kaufman.6. O. NAVAUX. B. Springer – Verlag. Berlin. 1997.h> // -// Definições para o sistema #define MAX_MSG_SIZE 256 //tamanho máximo das mensagens #define RANK_SERVER 0 //índice do processo que é servidor #define MSG_UPDATE 0 //msg de worker para atualziar caminho mínimo #define MSG_RECVTASK 1 //msg de worker pedindo por uma tarefa #define MSG_SENDTASK 2 //msg de worker desejando enviar uma tarefa #define MSG_TASK 3 //msg de server respondendo com uma tarefa #define MSG_NOTASK 4 //msg de server respondendo que não tem tarefa #define MSG_INIT 5 //msg de server com os dados iniciais do problema #define MSG_STOP 6 //msg de worker dizendo que terminou #define MSG_HAVEWORK 7 //msg de worker pedindo se ainda deve trabalhar #define MSG_WORK 8 //msg de server dizendo para worker trabalhar #define MSG_NOWORK 9 //server dizendo para worker parar de trabalhar #define MSG_NONE 10 #define MSG_END '#' //marca de final de mensagem // Forward das estruturas e funções do programa void printPacket(char* packet). nesse 10 . Curso. A.. São Paulo. 7. Inc. 518 p. 104p. Eduardo H. M. M.. [MPI00] The Message Passing Interface (MPI) standard.mcs. C.. J. E. SCHLEMER. R. IME-USP.com/docs/mpipro/index. 1990. ÁVILA. DE ROSE. //número de cidades nessa task int totalhops. A..Parallel Programming with MPI.anl. RP – 305 Outubro / 1999. [RIG99] RIGONI. [PAC97] PACHECO. DIVERIO. Introdução à programação em clusters de alto desempenho.J.c e salesman.gov/mpi (01 jul de 2000).h #include <time. VII 1990. R. P. //lista das cidades que estão nessa tarefa. BARRETO. P.. F. 1997. EUROPEAN PVM/MPI USERS GROUP MEETING (4).. J. 418 p. //número total de cidades do problema int length.mpi-softtech. MPI Software Technology. //tamanho do caminho dessa tarefa int *path. Introdução à complexidade de algoritmos paralelos. [MPI00] MPI/Pro – Help On-line . Disponível por WWW em http://www-unix. Recent Advances in Parallel Virtual Machine and Message Passing Interface. struct Task{ int hops. E.html (29 jun de 2000). UFRGS-PPGC. São Paulo. In: ESCOLA DE COMPUTAÇÃO. A. Disponível por WWW em http://www.WASNIEWSKI.. T. DONGARRA. Referências Bibliográficas [BUB97] BUBAK.. Anexo Código fonte dos arquivos salesman. [TER90] TERADA.

c // -// Introdução ao Processamento Paralelo e Distribuído // Programa: 'The Salesman Problem: Replicated Workers and a Bag of Tasks' // Implementação utilizando MPI: Messages Passsing Interface // Última modifcação: 30 de junho de 2000 // -// -#define _MPI //#define _DEBUG // -// -- 11 .int source). //tamanho do caminho mínimo encontrado int *shortestpath. char *Task_toPacket(struct Task *task).int *source.caminho struct Task *next. void Task_clonePath(int **dest. struct Task *Task_toTask(char *packet).int city. void Shared_stop(struct Shared *shared. void Worker_main(). char *Worker_toPacket(struct Worker *worker). void Shared_update(struct Shared *shared. //número de cidades do problema int **distancias. //matriz das distâncias entre as cidades }.. //funções associadas struct Shared *Shared_init(char *ndistfile.. //número de cidades do problema int **distancias. struct Worker *Worker_toWorker(char *packet). //indica quais workers estão parados int numliveworkers. //. //tempo de início do algoritmo time_t timeFinal.int size). //funções associadas char *Task_toString(struct Task *task)... void Shared_sendTask(struct Shared *shared. struct Worker{ int numcidades. // -- salesman. int Worker_visit(struct Worker *worker. void Task_free(struct Task *task).int source). //tempo de fim do algoritmo }. //lista com as tarefas a serem feitas time_t timeInicial. struct Shared{ int numworkers. //número de processos que ainda estão rodando int numcidades.struct Task *task).char *message). //funções associadas char *Worker_toString(struct Worker *worker).char *message). //o menos caminho struct Task *bag. void Shared_finalize(struct Shared **shared). }. void Task_push(struct Task **list. //distância entre as cidades int shortest.int nworkers).int nworkers). void Shared_haveWork(struct Shared *shared. void Shared_recvTask(struct Shared *shared. //. //númro de workers int *endworkers. char *Shared_toString(struct Shared *shared).struct Task *task).int source). void Shared_main(char* ndistfile. struct Task *Task_pop(struct Task **list).

h" #endif // -// -void printPacket(char* packet){ int i=0. } char* Task_toPacket(struct Task *task){ int i. struct Task *task..h" #include <stdio.tmp. } // Funções associadas a estrutura de dados Task char *Task_toString(struct Task *task){ int i.i<task->totalhops. } struct Task *Task_toTask(char* packet){ int i.. tmp = (char*) malloc(10*sizeof(char)).") Hops:[%d] Length:[%d]". //4: length[1] str[5] = (char) ((task->length&0x0000FF00)>>8).task->length). *tmp. strcat(str. 12 . str[7+i] = MSG_END. //3: length[0] ([0][1][2][3]) str[4] = (char) ((task->length&0x00FF0000)>>16).task->hops. return str.h> #include <stdlib.NULL. //6: length[3] for(i=0. printf("# (").tmp).// Biliotecas utilizadas #include "salesman. } printf(" )\n"). str[0] = (char) MSG_NONE.i++) str[7+i] = (char) task->path[i]. char *str.task->path[i]). //vai sempre o tipo da mensagem. task->hops = (int) packet[1]. task = (struct Task*) malloc(sizeof(struct Task)). //5: length[2] str[6] = (char) ((task->length&0x000000FF)>>0).h> #include <time. task->totalhops = (int) packet[2]."%d ".i<task->totalhops.h> #ifdef _MPI #include "mpi. while(packet[i]!=MSG_END){ printf(" %d".tmp). Task_clonePath(&(task->path). } sprintf(tmp. task->length = 0. strcpy(str. //1: número de cidades na task str[2] = (char) task->totalhops. str[3] = (char) ((task->length&0xFF000000)>>24). free(tmp). str = (char*) malloc(4*MAX_MSG_SIZE*sizeof(char)). char *str.h> #include <string.packet[i])."\tPath:( "). str = (char*) malloc(MAX_MSG_SIZE*sizeof(char)).task->totalhops). strcat(str. i++. return str. for(i=0.i++){ sprintf(tmp. str[1] = (char) task->hops.

shared->numworkers = nworkers. task->length += tmp<<16.i<size. return task. } // -// -// Funções associadas a estrutura de dados Shared struct Shared *Shared_init(char* ndistfile. else for(i=0.j=0. int size){ int i. tmp = (tmp<0)?(256+tmp):tmp. struct Shared *shared."r"))==NULL ){ printf("@ERRO FATAL: não foi possível abrir o arquivo.struct Task *task){ task->next = (*list).k<shared->numworkers. } struct Task *Task_pop(struct Task **list){ struct Task* task. (*dest) = (int*) malloc(size*sizeof(int)). for(k=0. tmp = (tmp<0)?(256+tmp):tmp. task->length += tmp<<8. tmp = (tmp<0)?(256+tmp):tmp. int* source.i++) task->path[i] = (int) packet[7+i].\n"). if( (handle = fopen(ndistfile. FILE* handle.k++) shared->endworkers[k] = 0. } void Task_clonePath(int **dest.i<size.i++) (*dest)[i] = 0. tmp = (int) packet[5]. task->length += tmp. free(task). free(shared). int valor. for(i=0. tmp = (int) packet[3]. shared->numliveworkers = nworkers. if( source!= NULL ) for(i=0.tmp = (int) packet[6]. tmp = (int) packet[4]. shared->endworkers = (int*) malloc(shared->numworkers*sizeof(int)). shared = (struct Shared*) malloc(sizeof(struct Shared)). (*list) = task. task = (*list). if ((*list)!=NULL) (*list) = (*list)->next.i<task->totalhops. { int i=0. return task. int nworkers){ int k. } void Task_free(struct Task *task){ free(task->path).i++) (*dest)[i] = source[i]. task->length += tmp<<24. tmp = (tmp<0)?(256+tmp):tmp. 13 . } void Task_push(struct Task **list.

shared->distancias = (int**) malloc(shared->numcidades*sizeof(int*)). } for(i=0. shared->distancias[i][j] = valor. printf("%s\n". for(i=0.shared->shortest).shared->numcidades).i<shared->numcidades. return shared. } void Shared_finalize(struct Shared **shared){ int i=0.j<shared->numcidades.j<shared->numcidades. tmp = (char*) malloc(80*sizeof(char))."%d\n". strcat(str. } sprintf(tmp.(*shared)->timeInicial)."%d\n".shared->distancias[i][j]).NULL. Task_clonePath(&(shared->shortestpath).j++){ fscanf(handle. 14 . sprintf(str. free(*shared)."\t#shortest: %d\n". }else{ fscanf(handle. } void Shared_update(struct Shared *shared. } } fclose(handle). strcat(str.tmp).tmp)."\t#shortestpath: ("). cidades: %d\n"."\n")."#Shared\n\t#num.i<shared->numcidades. for(j=0.*tmp.shared->numcidades).return NULL.i++){ shared->distancias[i] = (int*) malloc(shared>numcidades*sizeof(int)). printf("%s\n". free((*shared)->distancias)."\t#distancias: \n").i++) free((*shared)->distancias[i]).(*shared)->timeInicial)).char *message){ int i.tmp).tmp). strcat(str. struct Task *task. strcat(str. printf("#tempo final: %d\n". sprintf(tmp." %d"."%d ".difftime((*shared)>timeFinal.&valor). } char* Shared_toString(struct Shared* shared){ int i. for(i=0.i++){ sprintf(tmp. char *str.shared->shortestpath[i]).(*shared)->timeFinal).j++){ sprintf(tmp.i++){ sprintf(tmp.i<shared->numcidades. return str. printf("#tempo de processamento: %f(us)\n".Shared_toString((*shared))). for(i=0. strcat(str.j."\t\t")." )\n").tmp). printf("#tempo inicial: %d\n". for(j=0.tmp).\n").Shared_toString(shared)). shared->numcidades = valor. sprintf(tmp.&valor). str = (char*) malloc(2048*sizeof(char)). strcat(str. strcat(str. } sprintf(tmp. { printf("\n#algoritmo finalizado.i<(*shared)->numcidades. } strcat(str.tmp). } } shared->shortest = 10000.

#endif #endif Task_free(task).i<task->totalhops. message[0] = (char) MSG_NOTASK.task = Task_toTask(message).Task_toString(task)).end=1. #endif if( task->length<shared->shortest ) Task_push(&(shared->bag).MAX_MSG_SIZE. #ifdef _MPI MPI_Send(message. #ifdef _DEBUG printf("S_recvtask(%d): ". printPacket(message).Task_toString(task)).MSG_NONE.source).i++) shared->shortestpath[i] = task->path[i]. #ifdef _DEBUG printf("S_sendtask: %s\n". #ifdef _DEBUG printf("S_recvtask(%d): ". #endif #endif free(message). 15 .MPI_COMM_WORL D). } void Shared_recvTask(struct Shared *shared. #ifdef _MPI MPI_Send(message. for(i=0.MPI_UNSIGNED_CHAR.MSG_NONE. printPacket(message).MAX_MSG_SIZE. char *message.source). } void Shared_haveWork(struct Shared *shared. if ( ( task = Task_pop(&(shared->bag)) ) != NULL ){ message = Task_toPacket(task).int source){ shared->endworkers[source] = 1.MPI_COMM_WORL D). char *message.char* message){ struct Task *task.source. #ifdef _DEBUG printf("S_update: %s\n". message[0] = (char) MSG_TASK.MPI_UNSIGNED_CHAR. } Task_free(task).int source){ int i. #endif if( task->length<shared->shortest){ shared->shortest = task->length. message[1] = MSG_END.source. } } void Shared_sendTask(struct Shared *shared.int source){ struct Task *task. task = Task_toTask(message). else Task_free(task). free(message). }else{ message = (char*) malloc(2*sizeof(char)). } void Shared_stop(struct Shared *shared.task).

#ifdef _DEBUG printf("S_havework: "). message[0] = (char) MSG_INIT.MPI_UNSIGNED_CHAR. #ifdef _MPI MPI_Send(message. task->path[1] = i.i++) end &= shared->endworkers[i].MPI_COMM_WORLD).i<=shared->numworkers.i++){ task = (struct Task*) malloc(sizeof(struct Task)).nworkers))!=NULL ){ int i. 16 . message = Worker_toPacket(worker).i<=shared->numworkers.shared->numcidades). task->path[0] = 0.source. if ( (shared = Shared_init(ndistfile. shared->timeInicial = time(NULL).MSG_NONE.int nworkers){ struct Shared *shared. worker->distancias = shared->distancias. struct Task *task.task). #ifdef _MPI MPI_Send(message. printPacket(message). for(i=1.MAX_MSG_SIZE. }else{ message[0] = (char) MSG_WORK.message = (char*) malloc(2*sizeof(char)).NULL. for(i=1.MPI_COMM_WORL D).MAX_MSG_SIZE. task->totalhops = shared->numcidades. #ifdef _DEBUG printf("S_havework: "). #endif #endif shared->numliveworkers--. message[1] = MSG_END.MAX_MSG_SIZE.i++){ #ifdef _MPI MPI_Send(message.MPI_UNSIGNED_CHAR.MPI_UNSIGNED_CHAR. número de cidades e matriz de distâncias struct Worker *worker.source. for(i=1. printPacket(message).i<shared->numcidades. Task_push(&(shared->bag). char *message. Task_clonePath(&(task->path).i. int i. worker = (struct Worker*) malloc(sizeof(struct Worker)). task->length = shared->distancias[0][i]. worker->numcidades = shared->numcidades.MPI_COMM_WORL D).j.MSG_NONE. #endif #endif } free(message). } {//Enviando dados iniciais do problema. } void Shared_main(char* ndistfile. task->hops = 2. message[1] = MSG_END.MSG_NONE. if( end==1 ){ message[0] = (char) MSG_NOWORK.

MPI_UNSIGNED_CHAR. strcat(str. } }//END: for }//END: while }//Fim do algoritmo shared->timeFinal = time(NULL).tipomsg=0.tmp). while(shared->numliveworkers!=0){ for(i=1.MSG_NONE. #endif #endif tipomsg = (int) message[0]. cidades: %d\n". case MSG_HAVEWORK:{ Shared_haveWork(shared.MAX_MSG_SIZE. case MSG_SENDTASK:{ Shared_sendTask(shared. }break. } } // -// -// Funções associadas a estrutura de dados Worker char *Worker_toString(struct Worker *worker){ int i. str = (char*) malloc(2048*sizeof(char)). strcat(str. }break. case MSG_RECVTASK:{ Shared_recvTask(shared.i). sprintf(tmp. #ifdef _DEBUG printf("S_main (%d): ".i).source=0.j++){ sprintf(tmp.&st atus). switch(tipomsg){ case MSG_UPDATE:{ Shared_update(shared.MPI_COMM_WORLD.tmp).i++){ sprintf(tmp. }break."%d "."#Worker\n\t#num. strcat(str.i.i<=shared->numworkers.*tmp. printPacket(message).message). #endif message = (char*) malloc(MAX_MSG_SIZE*sizeof(char)). }break.i++){ #ifdef _MPI MPI_Recv(message.j. tmp = (char*) malloc(80*sizeof(char)).i<worker->numcidades.i).i). }break.worker->numcidades). char *str. inicialmente fica esperando requisição char *message.worker->distancias[i][j]). int origem=0.message).#endif } } {//Iniciando servidor de tarefas. for(j=0. case MSG_STOP:{ Shared_stop(shared.j<worker->numcidades."\t#distancias: \n"). #ifdef _MPI MPI_Status status."\t\t"). 17 . sprintf(str. Shared_finalize(&shared). for(i=0.tmp).

i++){ if(task->path[i]==city){ newlength = 0.MPI_COM 18 . *recvbuff. } return worker.j++){ str[2+(worker->numcidades*i)+j] = (char) worker->distancias[i][j].j. struct Worker *worker.i<worker->numcidades. for(i=0. time_t inicio.RANK_SERVER. worker->distancias = (int**) malloc(worker->numcidades*sizeof(int*)).i++){ worker->distancias[i] = (int*) malloc(worker->numcidades*sizeof(int)). worker = (struct Worker*) malloc(sizeof(struct Worker)). recvbuff = (char*) malloc(MAX_MSG_SIZE*sizeof(char)). struct Worker *worker.k=2. } str[k]=MSG_END.j++) worker->distancias[i][j] = (int) packet[2+(worker->numcidades*i)+j]. } return str.i<task->hops. int i. } int Worker_visit(struct Worker *worker. } return newlength. worker->numcidades = (int) packet[1]. sendbuff = (char*) malloc(MAX_MSG_SIZE*sizeof(char)). for(j=0.city. str[1] = (char) worker->numcidades. str[0] = (char) MSG_NONE.MAX_MSG_SIZE."\n"). } void Worker_main(){ char *sendbuff.*newTask. } } if( javisitada == 0 ){ newlength = task->length + worker->distancias[task->path[task->hops1]][city]. } struct Worker *Worker_toWorker(char *packet){ int i. } char *Worker_toPacket(struct Worker *worker){ int i.i<worker->numcidades. task->path[task->hops] = city. for(i=1.MPI_UNSIGNED_CHAR. //0: número de cidades for(i=0.javisitada=0.i++) for(j=0.newlength.working=1. char *str = (char*) malloc(MAX_MSG_SIZE*sizeof(char)). {//Recebendo dados iniciais do problema (instância de worker) #ifdef _MPI MPI_Recv(recvbuff. #ifdef _MPI MPI_Status status. javisitada = 1.newlength=0. return str.msgtipo. #endif struct Task *task. k++.j<worker->numcidades.} strcat(str.int city.j<worker->numcidades.MSG_NONE.struct Task *task){ int i=0.j.

Worker_toString(worker)).MPI_UNSIGNED_CHAR.MSG_NONE.M_WORLD. #ifdef _DEBUG printf("sendtask enviado\n"). newTask = (struct Task*) malloc(sizeof(struct Task)). #ifdef _DEBUG printPacket(recvbuff). #endif MPI_Send(l_sendbuff. printPacket(l_sendbuff). if( newlength==0 ){ //não faz nada.MPI_COMM_WORLD. if( msgtipo==MSG_TASK){ //tem tarefa para processar task = Task_toTask(recvbuff).city. Task_clonePath(&(newTask->path). newTask = (struct Task*) malloc(sizeof(struct Task)). #endif worker = Worker_toWorker(recvbuff). #endif for(city=1.Task_toString(task)). newTask->hops = task->hops+1.MAX_MSG_SIZE. #ifdef _DEBUG printf("%s\n".RANK_SERVER.RANK_SERVER. #endif #endif msgtipo = (int) recvbuff[0].&status). newTask->totalhops = task->totalhops.task->path. cidade já visitada }else{ if( (task->hops+1)<task->totalhops ){ char *l_sendbuff.MPI_UNSIGNED_CHAR.task). printf("%s\n".MSG_NONE. #endif #endif }else{ if( (task->hops+1)==task->totalhops ){ char *l_sendbuff.RANK_SERVER. #ifdef _MPI #ifdef _DEBUG printf("W_main: \n").MPI_C OMM_WORLD).city<task->totalhops. sendbuff[1] = MSG_END. #ifdef _MPI #ifdef _DEBUG printf("W_sendtask: ").MSG_NONE. #endif MPI_Sendrecv(sendbuff.MPI_UNSIGNED_CHAR.city++){ newlength = Worker_visit(worker.MAX_MSG_SIZE. 19 . #endif } while(working==1){ sendbuff[0] = (char) MSG_RECVTASK. newTask->length = newlength. #ifdef _DEBUG printf("W_task: %s\n".MAX_MSG_SIZE. printPacket(sendbuff).Task_toString(newTask)). recvbuff. l_sendbuff[0] = (char) MSG_SENDTASK.& status). l_sendbuff = Task_toPacket(newTask).task->totalhops).

#ifdef _MPI #ifdef _DEBUG printf("W_update: "). #ifdef _DEBUG printPacket(recvbuff).MSG_NONE.RANK_SERVER. l_sendbuff[0] = (char) MSG_UPDATE. Task_clonePath(&(newTask->path). #endif #endif msgtipo = (int) recvbuff[0]. printPacket(sendbuff).MPI_COM M_WORLD).MAX_MSG_SIZE.MSG_NONE. newTask->totalhops = task->totalhops. newTask->length = newlength + worker->distancias[newTask>path[newTask->totalhops-1]][0].newTask->hops = task->hops+1. #endif #endif } } }//END: else newlength=0 }//END: for city }else{ //não tem nenhuma tarefa no momento para processar sendbuff[0] = (char) MSG_STOP.MPI_UNSIGNED_CHAR. } }//END: while 20 . #ifdef _DEBUG printf("update enviado\n").MPI_COMM_WORLD.MPI_UNSIGNED_CHAR. l_sendbuff = Task_toPacket(newTask). #endif #endif inicio = time(NULL).task->totalhops).RANK_SERVER. #ifdef _DEBUG printf("stop enviado "). sendbuff[1] = MSG_END.RANK_SERVER. #endif MPI_Sendrecv(sendbuff. #ifdef _MPI #ifdef _DEBUG printf("W_stop: "). printPacket(sendbuff). while( time(NULL)-inicio<1 ).MPI_C OMM_WORLD).MAX_MSG_SIZE.MAX_MSG_SIZE.task->path. if(msgtipo==MSG_WORK) working = 1.& status). sendbuff[0] = (char) MSG_HAVEWORK.RANK_SERVER.MAX_MSG_SIZE. sendbuff[1] = MSG_END. else working = 0.MSG_NONE.MSG_NONE. #endif MPI_Send(sendbuff.MPI_UNSIGNED_CHAR. printPacket(l_sendbuff). recvbuff. #ifdef _MPI #ifdef _DEBUG printf("W_havetask: ").MPI_UNSIGNED_CHAR. #endif MPI_Send(l_sendbuff.

MPI_Comm_rank(MPI_COMM_WORLD.mpi_numprocess-1).&mpi_numprocess).char** argv){ int i.&argv). } #ifdef _MPI MPI_Finalize().argv[i]). for(i=0. }else{ Worker_main(). #endif } return 0. printf("-----\n").i++) printf("%d: %s\n".&mpi_myrank). printf("-----\n"). //número de processos rodando #ifdef _MPI MPI_Init(&argc.i. MPI_Comm_size(MPI_COMM_WORLD. { int mpi_myrank. } // -- 21 . //número do processo atual int mpi_numprocess. #endif if( mpi_myrank==RANK_SERVER ){ Shared_main(argv[1].} // -// -// Programa principal int main(int argc.i<argc.

Sign up to vote on this title
UsefulNot useful