O problema descreve dois processos, o produtor e o consumidor, que compartilham um buffer de tamanho fixo. O trabalho do produtor é gerar um dado, colocá-lo no buffer e repetir essa operação indefinidamente. Ao mesmo tempo, a tarefa do consumidor é consumir tais dados (i.e. removendo do buffer), um de cada vez.
O problema consiste em assegurar que o produtor não irá tentar adicionar dados no buffer quando este estiver cheio, e que o consumidor não tentará remover dados quando o buffer estiver vazio.
A solução para o produtor é dormir quando o buffer estiver cheio. Na próxima vez que o consumidor remover um item do buffer, ele irá acordar o produtor, que continuará a colocar dados no buffer. Da mesma forma, o consumidor dorme quando encontra o buffer vazio. Na próxima vez que o produtor adicionar um dado no buffer, ele acordará o consumidor.
O problema pode ser generalizado para múltiplos produtores e múltiplos consumidores.
Para esta experiência, foi resolvido o problema do produtor-consumidor apenas para 1 produtor e 1 consumidor. A implementação foi feita utilizando-se pipes, os quais possuem seu próprio buffer interno. Foi assumido que os pipes são thread-safe (i.e., garantem a exclusão mútua e eliminam condições de disputa) visto que isto é previsto, de acordo com o padrão POSIX.
Vale ressaltar que, como o tamanho padrão do buffer interno do pipe é de 5Kbytes (muito grande), não foi possível, através da execução do programa implementado, visualizar a ocorrência de buffer cheio, previsto no problema do produtor-consumidor. No entanto, assumiu-se que a implementação do pipe, de acordo com o padrão POSIX, lida com a situação de buffer cheio adequadamente.
A saída para o programa pode ser verificada na figura abaixo:
(clique na figura para melhor visualização)
Código:
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#define READ 0
#define WRITE 1
#define TRUE 1
/* protótipos */
void cria_item(int i);
void consome_item(int i);
void produtor(int fd[2], int qtde_itens);
void consumidor(int fd[2]);
int main (){
int fd[2];
/* criando pipe */
pipe (fd);
/* criando novo processo */
int pid = fork();
if (pid == -1) {
perror("Erro ao criar um novo processo!");
} else if (pid == 0) {
/* o novo processo funciona como produtor */
produtor(fd, 15);
} else {
/* o processo pai funciona como consumidor */
consumidor(fd);
}
return 0;
}
void produtor(int fd[2], int qtde_itens) {
close(fd[READ]);
int i, bytesEscritos;
for (i = 1 ; i <= qtde_itens; i++) {
sleep( rand() % 5 );
cria_item(i);
/* escreve no pipe */
bytesEscritos = write(fd[WRITE], &i, sizeof(int));
if (bytesEscritos == -1) {
perror("Erro de escrita no pipe!");
}
}
close (fd[WRITE]);
}
void consumidor(int fd[2]){
close (fd[WRITE]);
int i, bytesLidos;
while (TRUE) {
/* lê do pipe */
bytesLidos = read (fd[READ], &i, sizeof(int));
sleep( rand() % 5 );
consome_item(i);
if (bytesLidos == -1) {
perror("Erro de leitura no pipe!");
} else if (bytesLidos == 0) {
break;
}
}
close (fd[READ]);
}
void cria_item(int i){
printf("Produtor criou o %d.o item.\n", i);
}
void consome_item(int i){
printf("Consumidor consumiu o %d.o item.\n", i);
}
Fontes:
http://en.wikipedia.org/wiki/Producer-consumer_problemSistemas Operacionais Modernos, 2a ed - A.S.Tanenbaum
No comments:
Post a Comment