/*********************************************************************************** * * Este programa não faz parte do curso sobre tempo real do Laboratorio Embry-Riddle * embora tenha sido inspirado pelos demais experimentos que fazem parte. * * Experimento # 5 na disciplina de Sistemas Operacionais da PUC-Campinas * Originalmente programado por Florian Weizenegger * Data: 25/08/2003 * * Proposito: O proposito deste programa e o de permitir ao aluno perceber * o que vem a ser um thread, de maneira tal que consiga distingui-lo de * um processo. Além disso, são usados os principais comandos para criação * e manipulação de threads. * O problema dos produtores e consumidores sobre um buffer circular é * usado como assunto, permitindo que o aluno experimente duas implementações * diferentes para sua solução. Desta maneira, além dos threads propriamente * ditos, tambem locks e semaforos sao usados para garantir sincronizacao * de threads. * *************************************************************************************/ /* * Includes Necessarios */ #include /* for gettimeofday() */ #include /* para poder manipular threads */ #include /* para printf() */ /* * Constantes Necessarias */ #define NUM_THREADS 1 #define SIZEOFBUFFER 100001 #define NO_OF_ITERATIONS 100000 #define MICRO_PER_SECOND 1000000 /* * O tipo pthread_t permite a declaração de uma variável que recebe * um id quando o thread é criado. Posteriormente, esse id pode ser * usado em comandos de controle para threads. * Seguem dois vetores para ids, para um numero de threads igual a * constante NUM_THREADS */ pthread_t consumers[NUM_THREADS]; pthread_t producers[NUM_THREADS]; /* Tipo mutex, exclusao mutua */ pthread_mutex_t mutex; /* * Variaveis Necessarias */ int maior_errop = 0; int maior_erroc = 0; float maior_tempo = 0.0; int buffer[SIZEOFBUFFER]; /* Este e o buffer circular */ int *start; /* apontara para a primeira posicao do buffer */ int *rp; /* e o apontador para consumir o proximo item do buffer */ int *wp; /* e o apontador para produzir o proximo item do buffer */ /*Estruturas necessarias para tomada de tempo*/ struct timeval tempo_main; struct timeval tempo_produtor; struct timeval tempo_consumidor; struct timeval tempo_criacao; /* * Rotina para produzir um item toAdd no buffer */ int myadd(int toAdd) { //verificacao se o buffer nao esta cheio if ((rp != (wp+1)) && (wp != rp + SIZEOFBUFFER - 1)) { *wp = toAdd; wp++; //verificacao se wp chegou a ultima posicao do buffer if (wp == (start + SIZEOFBUFFER)) { wp = start; /* realiza a circularidade no buffer */ } return 1; } else return 0; } /* * Rotina para consumir um item do buffer e coloca-lo em retValue */ int myremove() { //verificacao se o buffer nao esta vazio if (wp != rp) { int retValue = *rp; rp++; //verificacao se rp chegou a ultima posicao do buffer if (rp == (start + SIZEOFBUFFER)) { rp = start; /* realiza a circularidade no buffer */ } return retValue; } else return 0; } /* * A rotina produce e responsavel por chamar myadd para que seja * colocado o valor 10 em uma posicao do buffer NO_OF_ITERATIONS vezes */ void *produce(void *threadid) { float tempop = 0.0; int contp =0; int i = 0; int sum = 0; int ret = 0; printf("Produtor #%d iniciou...\n", threadid); while (i < NO_OF_ITERATIONS) { pthread_mutex_lock (&mutex); ret = myadd(10); if (ret) { i++; sum += 10; }else contp++; pthread_mutex_unlock (&mutex); } printf("Soma produzida pelo Produtor #%d : %d\n", threadid, sum); printf("Soma NAO produzida pelo Produtor #%d : %d\n", threadid, contp); if (contp > maior_errop) maior_errop = contp; /*Pega o instante de tempo que Produtor termina*/ gettimeofday(&tempo_produtor,NULL); /*calcula o tempo de termino do produtor*/ tempop = (tempo_produtor.tv_sec); tempop = (tempo_produtor.tv_usec)/(float)MICRO_PER_SECOND; printf("Inst Tempo Fim Produtor = %.12f s\n\n", tempop); if (tempop > maior_tempo) { maior_tempo = tempop; } pthread_exit(NULL); } /* * A rotina consume e responsavel por chamar myremove para que seja * retorando um dos valores existentes no buffer NO_OF_ITERATIONS vezes */ void *consume(void *threadid) { float tempoc = 0.0; int contc = 0 ; int i = 0; int sum = 0; int ret = 0; printf("Consumidor #%d iniciou...\n", threadid); while (i < NO_OF_ITERATIONS) { pthread_mutex_lock (&mutex); ret = myremove(); if (ret != 0) { i++; sum += ret; }else contc ++; pthread_mutex_unlock (&mutex); } printf("Total consumido pelo Consumidor #%d : %d\n", threadid, sum); printf("Total NAO consumido pelo Consumidor #%d : %d\n", threadid, contc); if (contc > maior_erroc) maior_erroc = contc; /*Pega o instante de tempo que Consumidor termina*/ gettimeofday(&tempo_consumidor,NULL); /*calcula o tempo de criacao*/ tempoc = (tempo_consumidor.tv_sec); tempoc = (tempo_consumidor.tv_usec)/(float)MICRO_PER_SECOND; printf("Inst Tempo Fim Consumidor = %.12f s\n\n", tempoc); if (tempoc > maior_tempo) { maior_tempo = tempoc; } pthread_exit(NULL); } /* * Rotina Principal (que tambem e o thread principal, quando executada) */ int main(int argc, char *argv[]) { float tinicial = 0.0; float tfinal = 0.0; float tthreads = 0.0; int tp, tc; int i; start = &buffer[0]; wp = start; rp = start; /* iniciar controlador de exclusao mutua */ pthread_mutex_init(&mutex, NULL); /*Pega o instante de tempo de criacao das threads*/ gettimeofday(&tempo_criacao, NULL); /*calcula o tempo de criacao*/ tinicial = ( tempo_criacao.tv_sec ); tinicial = (tempo_criacao.tv_usec)/(float)MICRO_PER_SECOND; printf("\n\nInst Tempo Criacao da Threads: %.12f s\n\n", tinicial); for (i=0;i maior_tempo) { maior_tempo = tfinal; } printf("Inst Tempo Fim da Main: %.12f s\n\n", tfinal); //durme para dar tempo das outras threads acabarem sleep(5); //Calculando os tempos tthreads = (maior_tempo - tinicial); printf("Inst tempo do Ultimo a terminar(em s) %.12f s\n", maior_tempo); printf("\n\n===== Tempos de duracao das Threads======\n"); printf("Diferenca de tempo das threads (maior tempo - inicial): %.12f s\n", tthreads); printf ("Maior Numero de Erros de Algum Produtor: %d \n",maior_errop); printf ("Maior Numero de Erros de Algum Consumidor: %d \n",maior_erroc); pthread_exit(NULL); }