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.687 ]

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

Bug afeta todas as distros

Alocação dinâmica

Programação com números inteiros gigantes

Dynamic libraries com libtool

Algum humor e C++ Design Patterns (parte 2)

  
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