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: 98.435 ]

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


A solução, uma breve introdução



Para que se pudesse obter um material didático e de fácil entendimento, foram feitos alguns requisitos que julgaram-se necessários no projeto:
  • O programa deve ter um buffer limitado, acessível a qualquer processo decorrente do processo principal;
  • O programa deve ter uma fila apontando para o próximo endereço livre, a ser escrito;
  • O programa deve ter uma fila apontando para o próximo endereço ocupado, a ser lido e liberado;
  • O programa deve controlar as seções críticas (Compartilhamento de memória), para que não haja acessos ilegais.
  • O programa deve ter a capacidade de colocar um processo em modo de espera;
  • O programa deve ter a capacidade de controlar quando um processo está em espera, para poder "chamar" o mesmo;
  • O programa deve controlar quantos endereços estão livres e quantos endereços estão ocupados.

Levando em consideração esses dados, já se tem boa parte do desenvolvimento do projeto, basta apenas conhecer as bibliotecas usadas.

Recursos:

A biblioteca mais importante do projeto foi a pthread.h, que nos proporciona a possibilidade de programação concorrente com as funções de: controle de threads, criação de threads, suspensão de threads, execução e controle de exclusão mútua por semáforos binários, para controle da seção crítica. Para maiores informações visite o site www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html, de onde pesquisei todo material necessário.

Estrutura da fila:

A fila (FIFO) que controla o acesso ao buffer é formada apenas por: informação da posição atual e apontamento para próxima posição. A necessidade de se criar uma fila surgiu quando, o tempo de produzir ou de ler era diferente, gerando mais produção que leitura ou mais leitura que produção, então cada espaço do buffer que é produzido ou lido entra em uma fila e espera sua vez.

typedef struct apontador{ /* Estrutura que aponta para nova posição de leitura ou escrita.. e mantém a ordem em uma fila */
   int livre; /* Posição do buffer */
   struct apontador *prox; /* Próxima posição do buffer */
}APONTA;

Definições globais:

Para que houvesse o compartilhamento de memória entre os processos, foram definidas algumas variáveis e funções globais controladas por semáforos, para não haver indevidos acessos aos mesmos:

#define MAXBUFF 8 /* Máximo de buffer livre */
#define DORMINDO 0 /* Status atual do processo suspendido */
#define ACORDADO 1 /* Status atual do processo em execução */
#define ACABADO 0 /* Controle de processamento, 0 indica que produtor está produzindo */
#define PROCESSANDO 1 /* Controle de processamento, 1 indica que produtor já acabou */

APONTA *fila_leitura_inicio = NULL, *fila_leitura_fim = NULL; /* Fila que controla buffer livre de leitura */
APONTA *fila_escrita_inicio = NULL, *fila_escrita_fim = NULL; /* Fila que controla buffer livre de escrita */

void *Consumir(void* texto); /* Função do consumidor */
void *produz(void* texto); /* Função do produtor */
int setFila(int posicao, APONTA **begin, APONTA **end); /* Adiciona posição a fila que controla posições livres/ocupadas */
int getFila(APONTA **begin, APONTA **end); /* Remove posição a fila que controla posições livres/ocupadas */

char bufferLimitado[MAXBUFF]; /* Buffer de trabalho */
int buff_empty = MAXBUFF; /* Quantidade de endereços do Buffer livre */
int buff_full = 0; /* Quantidade de endereços do Buffer ocupado */
int status_produz = ACORDADO; /* Status atual do produtor é acordado */
int status_consome = ACORDADO; /* Status atual do consumidor é acordado */
int status_processamrnto = PROCESSANDO; /* Inicia status ativo de processamento */

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; /* Mutex (Semáforo) que controla o acesso ao buffer*/
pthread_mutex_t mutex_status_buff = PTHREAD_MUTEX_INITIALIZER; /* Mutex (Semáforo) que controla a espera(dormir/acordar)*/
pthread_cond_t status_produtor = PTHREAD_COND_INITIALIZER; /* Suspende execução da Thread produtor*/
pthread_cond_t status_consumidor = PTHREAD_COND_INITIALIZER; /* Suspende execução da Thread consumidor*/

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

Dynamic libraries com libtool

Tutorial SFML

Programação de Jogos com SDL

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

Compilando o Mono 2.2 no Ubuntu 8.10

  
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