Anúncio
Projeto de Controlo de Silo para Parqueamento
Projeto de Controlo de Silo para Parqueamento
Projeto de Controlo de Silo para Parqueamento
Projeto de Controlo de Silo para Parqueamento
Anúncio
Projeto de Controlo de Silo para Parqueamento
Projeto de Controlo de Silo para Parqueamento
Projeto de Controlo de Silo para Parqueamento
Projeto de Controlo de Silo para Parqueamento
Projeto de Controlo de Silo para Parqueamento
Anúncio
Projeto de Controlo de Silo para Parqueamento
Projeto de Controlo de Silo para Parqueamento
Projeto de Controlo de Silo para Parqueamento
Projeto de Controlo de Silo para Parqueamento
Projeto de Controlo de Silo para Parqueamento
Próximos SlideShares
Aula01Aula01
Carregando em ... 3
1 de 14
Anúncio

Mais conteúdo relacionado

Anúncio

Similar a Projeto de Controlo de Silo para Parqueamento(20)

Anúncio

Último(20)

Projeto de Controlo de Silo para Parqueamento

  1. 1 Projeto de Sistemas Operativos Simulador de Silo de Automóveis Fase 3 – Jan. 2011 Hugo Rodrigues Hugo.rodrigues@gmail.com
  2. 2 INDICE INDICE.......................................................................................................................................... 2 Introdução.................................................................................................................................... 3 1 – Simulador de Entrada de Viaturas em Massa .................................................................. 4 2 – Segurança de dados ............................................................................................................ 5 3 – Sincronização de acesso e permanência .......................................................................... 6 4 – Código da aplicação............................................................................................................. 7
  3. 3 Introdução Neste trabalho pretendeu-se criar uma aplicação para servir como subsistema de gestão de recursos em bibliotecas. O objectivo do projecto será a construção de um simulador para os problemas de um silo para estacionamento automóvel. O silo irá ter vários andares que comunicam entre si e também várias entradas e saídas. O projecto será realizado em várias fases, ao longo das quais se irão introduzir requisitos funcionais mais elaborados para a cuja resolução teremos de usar os recursos do Sistema Operativo (vamos continuar a usar o Linux). Procuramos na nossa implementação utilizar os conceitos aprendidos nas aulas teóricas e tirar partido dos mecanismos da linguagem C para reutilização e optimização de código.
  4. 4 1 – Simulador de Entrada de Viaturas em Massa Construir um pequeno programa multithreaded para enviar veículos para as quatro entradas do silo, em simultâneo. O programa deverá enviar rajadas de matrículas, distintas, sequenciais, em número a definir como parâmetro na linha de comando. Os veículos saídos do silo deverão ser registados, com o respectivo tempo de saída, ou alternativamente, o tempo em que permaneceram no silo. O objectivo é verificar que os veículos entrados são consistentes com os que saem. Se optou por efectuar as saídas ao fim de um tempo aletório, poderá ser conveniente modificar o output do simulador para emitir eese tempo de saída de cada veículo, juntamente com a respectiva matrícula. Para realizarmos este exercício efectuamos uma aplicação que através da linha de comandos recebe um número que corresponde à quantidade de matrículas a gerar. A quantidade de matrículas é limitada entre A e Z, sendo essa condição testada no programa. Para a geração da quantidade de matrículas foi criado um algoritmo que gera sequencialmente uma matrícula. A sequência tem um inicio, e via incrementando de forma circular. As matrículas geradas são colocadas num Fifo que corresponde a uma das entradas do silo (entrada é designada na linha de comando). O envio é efectuado através de Threads, pelo que foi necessário recorrer a um mutex por forma a controlar a concorrência sobre as variáveis de posição de letras / dígitos da matrícula. O código do simulador de entradas corresponde ao ficheiro Gerador_Matriculas.c
  5. 5 2 – Segurança de dados Planear e implementar os mecanismos de sincronização necessários para oferecer as garantias a) e b) referidas na introdução: a) garantir que nenhum veículo desaparece b) garantir que a marca de tempo quando um veículo entra não é corrompida ou alterada por outro veiculo Para realizarmos este exercício, planeamos efectuar alterações no core da aplicação de forma a podermos garantir a sincronização de escritas e leituras em zonas comuns aos vários threads através da utilização de um mutex. Desta forma é possível reservar o tempo de actuação sobre uma secção crítica em que os restantes processos aguardam pelo fim do processo que está em utilização. Logo nenhum veículo desaparece por não haver escritas simultâneas. Também quando um veículo entra no silo, a sua hora não é alterada porque faz parte da estrutura do tipo de dados que é armazenada. Os dados são por isso geridos através uma estrutura de lugar que tem um apontador para o veículo armazenado. Esta estrutura é manipulada pelos threads que com base no princípio anterior não modificam simultaneamente o conteúdo de um lugar.
  6. 6 3 – Sincronização de acesso e permanência Planear e implementar os mecanismos de sincronização necessários para oferecer as garantias c) d) e e) referidas na introdução. Estes são requisitos avançados. c) garantir que não entre nenhum veiculo quando o parque está cheio d) garantir que nenhum veículo fica indefinidamente no parque e) garantir que, se decidirmos encerrar o parque nenhum veículo em trânsito fica lá dentro. O planeamento destes mecanismos passou por implementar como no exercício anterior mutex que sinalizam a reserva de acções sobre secções críticas. Também recorremos a variáveis binárias e a métodos específicos para gerirem os eventos. Para garantirmos que nenhum veículo entra quando o parque se encontra cheio, no momento de guardarVeiculo procurar o primeiro lugar vazio, consideramos que esta parte da operação seja uma secção crítica, controlada com um mutex, e como tal não é possível haver concorrência nesse momento com outros threads nomeadamente os que colocam veículos na fila de saída. Para garantirmos que nenhum veículo fica indeterminadamente no silo, cada vez que um veículo é guardado é associado um thread com temporizador de saída removerVeiculo. Com estes threads activos, a aplicação Main não encerra sem que seja feito o respectivo join de todos eles. Assim, nenhum veículo ficará perdido. Para garantirmos que nenhum veículo fica no silo, acrescentámos uma variável binária “fechado” a qual é utilizada pela gestão de entradas para aceitar ou não veículos durante a transição de encerramento para fecho finalizado.
  7. 7 4 – Código da aplicação Aplicação para gerar e enviar através de um Fifo matrículas para uma entrada: Gerador_Matriculas.c #include <errno.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_BUF_SIZE 255 #define PIPE_IN "/tmp/SiloEntrada%d" int matriculas; int max_matriculas; pthread_mutex_t mutex; // Caracteres iniciais para as matrículas // Vamos gerar algo do tipo LetraLetra-Numero-Numero // Geração é sequêncial char p1 = 'A', p2 = 'A', p3 = '0', p4 = '0', p5 = '0', p6 = '0'; void verificaDigitoMatricula(char *digit, char *hdigit, char limit, char reset) { if (*digit > limit) { *digit = reset; *hdigit = *hdigit + 1; } } char calculaMatricula(char *matricula) { pthread_mutex_lock(&mutex); // entra na secção crítica p6++; // nota p6 é variável global e está por isso numa secção crítica verificaDigitoMatricula(&p6, &p5, '9', '0'); verificaDigitoMatricula(&p5, &p4, '9', '0'); verificaDigitoMatricula(&p4, &p3, '9', '0'); verificaDigitoMatricula(&p3, &p2, '9', '0'); verificaDigitoMatricula(&p2, &p1, 'Z', 'A'); if (p1 > 'Z') {// se a posição da Letra da matricula ultrapassa o limite Z termina geração printf("Limite de matriculas possíveis foi atingidon"); exit(-1); } // atribui os valores de cada posição da matricula na memória matricula[0] = p1; matricula[1] = p2; matricula[2] = '-'; matricula[3] = p3; matricula[4] = p4; matricula[5] = '-'; matricula[6] = p5; matricula[7] = p6; pthread_mutex_unlock(&mutex); // sai da secção crítica
  8. 8 } void *criarFifo(void *threadid) { char fifo[13]; char matricula[9]; int taskid, ret_val, wrfd; taskid = (*(int *) threadid); sleep(1); // necessário para sincronizar os threads snprintf(fifo, sizeof (fifo), PIPE_IN, taskid + 1); ret_val = mkfifo(fifo, 0666); if ((ret_val == -1) && (errno != EEXIST)) { perror("Error creating named pipen"); exit(-1); } wrfd = open(fifo, O_WRONLY); printf("fifo %s criadon", fifo); for(;;) { if (matriculas++ > max_matriculas) break; // Verifica se atingimos o limite de geração de matrículas calculaMatricula( &matricula ); // Obtem uma matricula printf("Thread %d: %s (%d/%d)n", taskid, matricula, matriculas, max_matriculas); write(wrfd, matricula, 9); } pthread_exit(NULL); } int main(int argc, char *argv[]) { int numThreads = 4; // Lança 4 Threads - 1 para cada piso pthread_t threads[numThreads]; int *taskids[numThreads]; int thr; if (argc != 2) { printf("Passe os seguintes parâmetros: %s <Nº de Matriculas a gerar> n", argv[0]); exit(-1); } max_matriculas = atoi(argv[1]); // Nº de matrículas a gerar for (thr = 0; thr < numThreads; thr++) { // Para cada piso cria um novo thread taskids[thr] = (int *) malloc(sizeof (int)); *taskids[thr] = thr; printf("Thread %dn", thr); int res = pthread_create(&threads[thr], NULL, criarFifo, (void *) taskids[thr]); if (res) { printf("Erro a criar thread - code: %dn", res); exit(-1); } } pthread_exit(NULL); }
  9. 9 Aplicação Core do Silo: Core.c #include <stdio.h> #include <errno.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <signal.h> #include <sys/ipc.h> #include <pthread.h> #define MAX_BUF_SIZE 9 #define PIPE_IN "/tmp/SiloEntrada%d" #define PIPE_OUT "/tmp/SiloSaida" /* * Definição de Chave para o segmento de memória * */ #define KEY (66661) /* * Definição de limites globais para utilização na aplicação */ #define MAX_PISOS 4 #define MAX_POSICOES 10 /* * Estrutura do silo para armazenamento de veículos * * O silo tem vários andares * Tem em cada andar várias posições * * Cada matrícula de veículo corresponde a uma identidade * */ typedef struct Lugar { char matricula[MAX_BUF_SIZE]; // Texto da matrícula do veículo time_t hora; // Hora de entrada de veículo } lugar_t; typedef struct threadedLugar { lugar_t* lugar; pthread_t tid; } tlugar_t; /* * Variavel global correspondente à estrutura do silo * Silo com 4 andares e 10 lugares cada um */ static lugar_t* plugares; /* * Variavel global buffer de entrada por piso */ char buf[MAX_PISOS][MAX_BUF_SIZE];
  10. 10 tlugar_t tlugares[MAX_PISOS][MAX_POSICOES]; pthread_mutex_t mutex; char fechado = 0; void initLugares() { int i, j; lugar_t *l; l = plugares; for (i = 0; i < MAX_PISOS; i++) // Limpa todas as posições for (j = 0; j < MAX_POSICOES; j++, l++) { l->hora = 0; l->matricula[0] = '0'; } } void outLugares() { int i, j; lugar_t *l; l = plugares; for (i = 0; i < MAX_PISOS; i++) for (j = 0; j < MAX_POSICOES; j++, l++) { printf("%d,%d Hora: %d Matricula: %sn", i, j, l->hora, l->matricula); } } /* * generates a psuedo-random integer between 0 and max */ int randint(int max) { return (int) (rand() % max); } void *removerVeiculo(void* tlugarArg) { int seconds; int fd, ret_val; tlugar_t *tlugar = (tlugar_t*) tlugarArg; seconds = (randint(10) + 1); printf("A aguardar %d segundos para remover a matricula %s tid %dn", seconds, tlugar->lugar->matricula, tlugar- >tid); sleep(seconds); // Aguarda para remover automaticamente a matricula do silo ret_val = mkfifo(PIPE_OUT, 0666); if ((ret_val == -1) && (errno != EEXIST)) { perror("Error creating named pipen"); exit(-1); } fd = open(PIPE_OUT, O_WRONLY); // Envia a matricula pelo Pipe de saída write(fd, tlugar->lugar->matricula, MAX_BUF_SIZE); printf("Matricula %s removida. tid(%d)n", tlugar->lugar->matricula, tlugar->tid); tlugar->lugar->hora = 0; // Limpa o lugar no silo tlugar->lugar->matricula[0] = NULL; pthread_exit((void*) tlugar->tid);
  11. 11 } void encerrarSilo() { int i, j, fd; lugar_t *l = plugares; pthread_mutex_lock(&mutex); // Escreve na memória for (i = 0; i < MAX_PISOS; i++) { // Limpa todos os veículos no silo quando este encerra for (j = 0; j < MAX_POSICOES; j++, l++) { if (l->hora > 0) { /* Abre o Pipe para escrita */ fd = open(PIPE_OUT, O_WRONLY); /* Escreve a matrícula para o pipe */ write(fd, l->matricula, MAX_BUF_SIZE); l->matricula[0] = NULL; l->hora = 0; } } } pthread_mutex_unlock(&mutex); } int guardaVeiculo(char *matricula) { pthread_t thread; int piso = 0, posicao = 0; lugar_t *l = plugares; tlugar_t *ptlugar; time_t curtime; curtime = time(NULL); struct tm *loctime; loctime = localtime(&curtime); pthread_mutex_lock(&mutex); // Inicio da secção crítica em que se mexe com a memória int i, j, encontrou = 0; for (i = 0; i < MAX_PISOS && encontrou == 0; i++) { // procura o primeiro lugar vazio for (j = 0; j < MAX_POSICOES && encontrou == 0; j++, l++) { if (l->hora == 0) { piso = i; posicao = j; encontrou = 1; } } } pthread_mutex_unlock(&mutex); // Fim da secção crítica em que se mexeu com a memória if (i == MAX_PISOS && j == MAX_POSICOES) // Se atingiu o máximo de posições termina { printf("Nao existem lugares livres para a matricula: %sn", matricula); return -1; } strncpy(l->matricula, matricula, MAX_BUF_SIZE); // Guarda matrícula l->hora = curtime;
  12. 12 ptlugar = &tlugares[i][j]; ptlugar->lugar = l; ptlugar->tid = i * MAX_POSICOES + j + MAX_PISOS + 1; printf("Matricula %s guardada: piso %d posicao %d tid %dn", matricula, piso, posicao, ptlugar->tid); pthread_create(&thread, NULL, removerVeiculo, (void *) ptlugar); // associa a cada veículo guardado uma thread para remover veículo return 1; } reservarMem() { int shmid; key_t key; int shmz = MAX_PISOS * MAX_POSICOES * sizeof (lugar_t); key = KEY; if ((shmid = shmget(key, shmz, IPC_CREAT | 0666)) < 0) { perror("shmget"); exit(1); } if ((plugares = shmat(shmid, NULL, 0)) == (char *) - 1) { perror("shmat"); exit(1); } } void *gereEntradaPiso(void *thread_id) { char *pipename; int tid, fd, numread; tid = (int) thread_id; pipename = malloc(strlen(PIPE_IN) + 2); sprintf(pipename, PIPE_IN, tid + 1); fd = open(pipename, O_RDONLY); for(;;) { numread = 0; numread = read(fd, buf[tid], MAX_BUF_SIZE); buf[tid][numread] = '0'; if (numread != 0 && strcmp(buf[tid], "x") == 0) // se for passado x termina ciclo { fechado = 1; encerrarSilo(); // Encerra o silo cada vez que receber a ordem pelo Fifo break; } if (fechado == 0 && numread != 0) { guardaVeiculo(buf[tid]); } } free(pipename); pthread_exit((void*) thread_id);
  13. 13 } int main(int argc, char *argv[]) { int t, rc; void *status; pthread_attr_t attr; srand(time(NULL)); // Cria aleatóriamente pthread_t threads[MAX_PISOS]; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); reservarMem(); // Trata da memória initLugares(); // Trata dos lugares for (t = 0; t < MAX_PISOS; t++) { rc = pthread_create(&threads[t], &attr, gereEntradaPiso, (void *) t); if (rc) { printf("Erro a criar thread - code: %dn", rc); exit(-1); } } pthread_attr_destroy(&attr); // Aguarda que todos os threads encerrem for (t = 0; t < MAX_PISOS; t++) { rc = pthread_join(threads[t], &status); if (rc) { printf("Erro a criar thread - code: %dn", rc); exit(-1); } printf("Thread %ld terminou - status %ld n", t, (long) status); } printf("Encerrar aplicação.n"); pthread_exit(NULL); } Aplicação para mostrar a Fila de saída do Silo: Output.c #include <stdio.h> #include <errno.h> #include <ctype.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #define PIPE_OUT "/tmp/SiloSaida" int main(int argc, char *argv[]) { int fd, readbytes;
  14. 14 char buffer[255]; for(;;) { // Lê do fifo num ciclo infinito as matriculas que saem do silo fd = open(PIPE_OUT, O_RDONLY); readbytes = read(fd, buffer, 255); buffer[readbytes] = '0'; if (readbytes != 0) { printf("Matricula Saída: %sn", buffer); } } }
Anúncio