O problema ocorre quando dois produtores tentam colocar objetos no buffer ao mesmo tempo ou quando dois consumidores retiram objetos do buffer ao mesmo tempo. A solução deve ser capaz permitir somente um produtor adcionando objeto e um consumidor retirando objeto ao mesmo tempo.
Também é necessário gerenciar as situações em que o buffer estpa cheio, impossibilitando uma nova adição, e quando está vazio, impossibilitando que um objeto seja consumido.
Na implementação aqui apresentada, utilizou-se os pipes do padrão posix, que possui todos os requerimentos necessários para o buffer. Por ser thread-safe, ele possibilita somente que um processo esteja adicionando objeto ao pipe e somenque um que esteja consumindo. Também já gerencia os casos em que o buffer está vazio ou cheio.
Nessa solução são criados 10 produtores que adionam um objeto ao pipe, que corresponde ao index que identifica o produtor. Em seguida, são criados 5 consumidores e após 6 segundos mais 10 produtores. Os consumidores estão sempre lendo o pipe até que seja esvaziado e então o processo é finalizado.
Abaixo segue o código da solução:
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include<unistd.h>
#define LER 0 //indexa a leitura no pipe
#define ESCREVER 1 //indexa a escrita no pipe
#define PRODUTORES 10; // define numero de produtores
#define CONSUMIDORES 5; // define numero de leitores
int fd [2];
void produtor( int produtor);
void consumidor(int consumidor);
void criar_consumidor(int consumidor);
void criar_produtor(int produtor);
main ()
{
int j = 0;
pipe (fd);
//cria produtores
int i = PRODUTORES;
for (j = 1; j <= i; j++)
{
criar_produtor(j);
}
//cria consumidores
i = CONSUMIDORES;
for (j = 1; j<= i; j++)
{
criar_consumidor(j);
}
sleep(6); //espera 6 s para produzir mais
i = PRODUTORES;
for (j = i +1 ; j <= 2*i; j++)
{
criar_produtor(j);
}
return 0;
}
void produtor(int produtor_id)
{
int bytes_escritos;
close(fd[LER]);
bytes_escritos = write (fd[ESCREVER],&produtor_id, sizeof(int));
if (bytes_escritos == -1) { //se ocorre erro fecha processo
printf("\nProblema na escrita do produtor %d", produtor_id);
exit(-1);
}
else{
printf("\nProdutor %d enviou mensagem", produtor_id); //conseguiu enviar mensagem
}
close (fd[ESCREVER]);
exit(0);
}
void consumidor(int consumidor_id)
{
int msg;
int bytes_lidos;
int max_zero;
while(1){
sleep(1); //intervalo de 1 s entre as leituras
close (fd[ESCREVER]);
bytes_lidos = read (fd[LER],&msg, sizeof(int));
if (bytes_lidos == 0){ //caso não tenha nada no pipe finaliza o processo
printf("\nConsumidor %d saiu", consumidor_id);
break;
}
else if (bytes_lidos == -1){//se ocorre erro na leitura, sai
printf("\nProblema na leitura do consumidor %d",consumidor_id );
exit(-1);
}
else printf("\nConsumidor %d leu mensagem: %d com %d bytes\n", consumidor_id, msg, bytes_lidos);
}
close(fd[LER]);
exit(0);
}
void criar_consumidor(int consumidor_id)
{
int pid;
pid = fork ();
if (pid == 0){//caso seja processo filho realiza operação de consumidor
consumidor(consumidor_id);
}
}
void criar_produtor(int produtor_id)
{
int pid;
pid = fork ();
if (pid == 0){//caso seja processo filho realiza operação de produtor
produtor(produtor_id);
}
}
O resultado é mostrado abaixo:
Produtor 1 enviou mensagem
Produtor 2 enviou mensagem
Produtor 3 enviou mensagem
Produtor 4 enviou mensagem
Produtor 5 enviou mensagem
Produtor 6 enviou mensagem
Produtor 7 enviou mensagem
Produtor 8 enviou mensagem
Produtor 9 enviou mensagem
Produtor 10 enviou mensagem
Consumidor 1 leu mensagem: 1 com 4 bytes
Consumidor 2 leu mensagem: 2 com 4 bytes
Consumidor 3 leu mensagem: 3 com 4 bytes
Consumidor 4 leu mensagem: 4 com 4 bytes
Consumidor 5 leu mensagem: 5 com 4 bytes
Consumidor 1 leu mensagem: 6 com 4 bytes
Consumidor 2 leu mensagem: 7 com 4 bytes
Consumidor 3 leu mensagem: 8 com 4 bytes
Consumidor 4 leu mensagem: 9 com 4 bytes
Consumidor 5 leu mensagem: 10 com 4 bytes
Consumidor 1 leu mensagem: 11 com 4 bytes
Produtor 11 enviou mensagem
Consumidor 3 leu mensagem: 12 com 4 bytes
Produtor 12 enviou mensagem
Consumidor 2 leu mensagem: 13 com 4 bytes
Produtor 13 enviou mensagem
Consumidor 4 leu mensagem: 14 com 4 bytes
Produtor 14 enviou mensagem
Consumidor 5 leu mensagem: 15 com 4 bytes
Produtor 15 enviou mensagem
Produtor 16 enviou mensagem
Produtor 17 enviou mensagem
Produtor 18 enviou mensagem
Produtor 19 enviou mensagem
Produtor 20 enviou mensagem
Consumidor 1 leu mensagem: 16 com 4 bytes
Consumidor 3 leu mensagem: 17 com 4 bytes
Consumidor 2 leu mensagem: 18 com 4 bytes
Consumidor 4 leu mensagem: 19 com 4 bytes
Consumidor 5 leu mensagem: 20 com 4 bytes
Consumidor 1 saiu
Consumidor 3 saiu
Consumidor 2 saiu
Consumidor 4 saiu
Consumidor 5 saiu
O resultado mostra que nenhum consumidor obteve uma mensagem igual, que nenhuma mensagem foi perdida e que as ordem em que as mensagens chegaram foi a mesmo em que foram enviadas.
Com o comando "ps -aux" no console do linux, pode-se ver informações sobre os processos decorrentes do programa executado. Abaixo segue o output:
david 7524 0.0 0.0 3780 368 pts/2 S+ 04:24 0:00 ./prod
david 7525 0.0 0.0 0 0 pts/2 Z+ 04:24 0:00 [prod]
david 7526 0.0 0.0 0 0 pts/2 Z+ 04:24 0:00 [prod]
david 7527 0.0 0.0 0 0 pts/2 Z+ 04:24 0:00 [prod]
david 7528 0.0 0.0 0 0 pts/2 Z+ 04:24 0:00 [prod]
david 7529 0.0 0.0 0 0 pts/2 Z+ 04:24 0:00 [prod]
david 7530 0.0 0.0 0 0 pts/2 Z+ 04:24 0:00 [prod]
david 7531 0.0 0.0 0 0 pts/2 Z+ 04:24 0:00 [prod]
david 7532 0.0 0.0 0 0 pts/2 Z+ 04:24 0:00 [prod]
david 7533 0.0 0.0 0 0 pts/2 Z+ 04:24 0:00 [prod]
david 7534 0.0 0.0 0 0 pts/2 Z+ 04:24 0:00 [prod]
david 7535 0.0 0.0 3784 244 pts/2 S+ 04:24 0:00 ./prod
david 7536 0.0 0.0 3784 244 pts/2 S+ 04:24 0:00 ./prod
david 7537 0.0 0.0 3784 244 pts/2 S+ 04:24 0:00 ./prod
david 7538 0.0 0.0 3784 244 pts/2 S+ 04:24 0:00 ./prod
david 7539 0.0 0.0 3784 244 pts/2 S+ 04:24 0:00 ./prod
david 7541 0.0 0.0 7472 912 pts/1 S+ 04:24 0:00 grep prod
Pode-se notar que alguns processo estão em estado zoobie (Z+) e outros estão dormindo (+S). Os processos domindo são os consumidores que dormiram em virtude do comando sleep(), os demais podem ser processos filhos, tanto consumidores ou produtores, que estão esperando o proceso finalizá-los.