O Produtor e o Consumidor

Este artigo tem por finalidade apresentar um problema clássico em sistemas operacionais, a relação "o produtor e o consumidor", que visa por em prática a gerência de processos concorrentes em um sistema operacional. Problema: um processo escreve em um buffer limitado, enquanto outro lê e limpa o mesmo, preservando a integridade dos dados.

[ Hits: 96.683 ]

Por: Ricardo Bocchi em 27/01/2010 | Blog: http://ricardobocchi.blogspot.com/


Lógica e estruturação da solução - o produtor



Início do programa:

O programa inicia com um buffer de 8 espaços na memória, já disparando as duas threads, uma para o produtor e outra para o consumidor.

O produtor:

O produtor é iniciado com uma lista de 23 (0-22) elementos (produto), letras de a-z para adicionar no buffer. Sua primeira ação é testar o acesso às variáveis que controlam a quantidade de espaço livre e de espaço ocupado, para ver se estão liberadas para uso, só aí então verificar se deve prosseguir produzindo ou se deve entrar em modo de espera:

/* Semáforo para definir status do produtor - Dormindo ou acordado */
pthread_mutex_lock(&mutex_status_buff);

if (buff_empty == 0 || buff_full == 8){ /* Se buffer vazio for 0, dorme */

   printf("\n[Produtor diz:] Vou dormir enquanto não tem trabalho!!\n");
   status_produz = DORMINDO;
   /* Enquanto não estiver onde escrever, processo dorme.. Só libera quando receber um sinal de que pode começar de novo*/
   pthread_cond_wait(&status_produtor, &mutex_status_buff); /* Em modo de espera, aguardando sinal */
   status_produz = ACORDADO; /* Depois de receber sinal, volta a produzir*/
   printf("\n[Produtor diz:] Tocou a campainha, vou trabalhar!!\n");

}

Se buffer estiver cheio, entra em modo de espera, até que o consumidor mande um sinal dizendo que há espaço livre no buffer. Repare que, quando o programa chega em pthread_cond_wait(&status_produtor, &mutex_status_buff), ele entra em modo de espera, pois essa é a função que coloca o processo neste estado, e só vai prosseguir quando receber um sinal, e quando isso acontecer já muda seu status para ACORDADO e libera as variáveis.

Se buffer estiver com posições livres, já libera as variáveis e segue para o próximo passo, que é preencher o buffer propriamente dito:

/* Semáforo para exclusão mutua que controla posições do buffer */
pthread_mutex_lock(&mutex);

buff_empty--; /* Decrementa espaço livre */
buff_full++; /* Incrementa espaço ocupado */

/*Recebe posição da fila, se retorno for -1 quer dizer que a fila não inicializou.. então ele deve pegar do controle do buffer*/
if ((posicao_buffer = getFila(&fila_escrita_inicio, &fila_escrita_fim)) == -1) /*pega posição livre do buffer*/
   posicao_buffer = buff_full;/* Se for inicio do programa a fila estará vazia, mas o buffer cheio. A fila pode ser inicializada no inicio do programa também */

/*Manda posição escrita para fila*/
if (setFila(posicao_buffer, &fila_leitura_inicio, &fila_leitura_fim) == -1) /*Adiciona na fila*/
   sprintf(stderr,"\n\nErro ao inserir na fila: %d!!\n\n", errno);

/*Preenche buffer*/
bufferLimitado[posicao_buffer] = abc[i];

printf("\n\n[Produtor diz:] Pid [%d] | Tid [%u] | Posição [%d] | %s [%c] \n",getpid(),(unsigned int)pthread_self(), posicao_buffer, (char*) texto, bufferLimitado[posicao_buffer]);

Nessa parte o sistema bloqueia as variáveis de controle de buffer, Empty e Full, busca a próxima posição livre da fila de escrita. Repare que se a fila estiver vazia, e há espaço livre no buffer, quer dizer que é o início do programa, a fila poderia ser iniciada antes das threads serem disparadas, mas para ficar de um melhor entendimento, a meu ver, optei por essa forma. Em seguida adiciona nova posição escrita (Ocupada) para a fila de leitura, e por fim, escreve o "produzido" na posição ocupada, mandando uma mensagem logo depois para avisar que há produção na fila.

pthread_mutex_lock(&mutex_status_buff);

if (status_consome == DORMINDO){ /* Se consumidor estiver dormindo, o acorda.. pois há produção no buffer*/

   printf("\n[Produtor diz:] O consumidor está dormindo, vou avisar que tem produto no buffer!!\n");
   sleep(rand() % 2);
   pthread_cond_signal(&status_consumidor); /* Envia um sinal para consumidor, e o acorda */

}

Antes de finalizar o processo o produtor verifica se o consumidor não está em período de espera, se estiver, é por que não havia nada no buffer quando ele executou, e agora o produtor deve enviar um sinal dizendo que há produção no buffer, para que o consumidor possa consumir. Se o consumidor não estiver em espera ele passa direto, liberando as variáveis bloqueadas. Pronto! acabou as verificações do produtor na primeira execução, agora ele reinicia o processo, até encerrar a produção. Depois de encerrar a produção:

status_processamento = ACABADO;
printf("\n[Produtor diz:] Meu trabalho acaba por aqui, vou produzir o ultimo e ir embora. Até..!!\n");

A última ação do produtor, antes de "ir embora", é avisar que acabou, setando o status de processamento para ACABADO. Assim quando consumidor chegar ao último item produzido poderá encerrar seu trabalho.

Página anterior     Próxima página

Páginas do artigo
   1. O problema, uma breve introdução
   2. A solução, uma breve introdução
   3. Lógica e estruturação da solução - o produtor
   4. Lógica e estruturação da solução - o consumidor
   5. Código comentado na íntegra
   6. Compilação e execução
Outros artigos deste autor
Nenhum artigo encontrado.
Leitura recomendada

Como funcionam os alocadores de memória do STD C?

Projeto Icecream (parte 1)

Instalando Facebook Folly através do Conan

Parâmetros interessantes do scanf e do printf em C

Bug afeta todas as distros

  
Comentários
[1] Comentário enviado por pink em 29/01/2010 - 12:51h

Ótimo, meus parabéns.... sem comentários....
Aguardo pelo próximo artigo....

[2] Comentário enviado por saitam em 15/05/2010 - 16:54h

Ótimo artigo bem didático. Parabéns
Aguardo pelo próximo artigo [2]

[3] Comentário enviado por Claudinei_Jr em 03/04/2013 - 18:06h

Ótimo Artigo, super didático!
Parabéns!
Contribuiu muito com minhas pesquisas sobre o assunto!!!


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts