DEV Community

Celso Costa
Celso Costa

Posted on

Producer/Consumer (Produtor/Consumidor)

Definição

Consideramos dois processos, chamados de “produtor” e “consumidor”, respectivamente. O produtor é um processo cíclico e cada vez que passa pelo seu ciclo produz uma determinada porção de informação, que deve ser processada pelo consumidor. O consumidor também é um processo cíclico e cada vez que passa pelo seu ciclo pode processar a próxima porção de informação, tal como foi produzida pelo produtor. Um exemplo simples é dado por um processo computacional, que produz como “porções de informação” imagens de cartões perfurados a serem perfurados por um cartão perfurado, que desempenha o papel do consumidor.[1]

Image description

Explicação

Um produtor cria itens e os armazena em uma estrutura de dados, enquanto um consumidor remove os itens dessa estrutura e os processa.

Se o consumo for maior que a produção o buffer(estrutura de dados) esvazia, e o consumidor não tem o que consumir
Se o consumo for menor que a produção o buffer enche, e o produtor não consegue adicionar mais itens. Esse é um problema clássico chamado de buffer limitado.

Contextualização do Problema

Suponha que temos um produtor que publica um e-mail no buffer, e um consumidor que consome o e-mail do buffer e exibe uma mensagem informando que foi enviado um e-mail com a nova senha de acesso para o e-mail informado.

Implementação em go


package main

import (
    "fmt"
    "os"
    "strconv"
    "sync"
    "time"
)

type buffer struct {
    items []string
    mu    sync.Mutex
}

func (buff *buffer) add(item string) {
    buff.mu.Lock()
    defer buff.mu.Unlock()
    if len(buff.items) < 5 {
        buff.items = append(buff.items, item)
        // fmt.Println("Foi adicionado o item " + item)
    } else {
        fmt.Println("O Buffer não pode armazenar nenhum item mais está com a capacidade máxima")
        os.Exit(0)
    }
}

func (buff *buffer) get() string {
    buff.mu.Lock()
    defer buff.mu.Unlock()
    if len(buff.items) == 0 {
        return ""
    }
    target := buff.items[0]

    buff.items = buff.items[1:]
    return target
}

var wg sync.WaitGroup

func main() {
    buff := buffer{}
    wg.Add(2)

    go producer(&buff)
    go consumer(&buff)
    wg.Wait()
}

func producer(buff *buffer) {
    defer wg.Done()
    for index := 1; ; index++ {
        str := strconv.Itoa(index) + "@email.com"
        buff.add(str)
        time.Sleep(5 * time.Millisecond) // Adiciona um pequeno atraso para simular produção
    }
}

func consumer(buff *buffer) {
    defer wg.Done()
    for {
        data := buff.get()

        if data != "" {
            fmt.Println("Enviado um email com a nova senha de acesso para: " + data)
        }
    }
}


Enter fullscreen mode Exit fullscreen mode

Explicando a implementação

  • Primeiro, criamos uma estrutura chamada buffer, que contém um array de strings chamado items e um mecanismo de controle do tipo mutex, chamado mu, para gerenciar o acesso concorrente.
  • Temos duas funções: uma chamada add, que basicamente adiciona um item ao buffer, desde que haja espaço disponível, já que a capacidade do buffer é de apenas 5 itens; e outra chamada get, que, se houver itens no buffer, retorna o primeiro elemento e remove esse elemento do buffer.
  • O Producer basicamente pega o index do loop e o concatena em uma string chamada str, que contém o índice e um domínio de e-mail fictício, e adiciona no buffer. Foi adicionado um intervalo de tempo para simular um atraso.
  • O Consumer solicita ao buffer um item, caso tenha ao menos um item. Em seguida, o Consumer exibe uma mensagem na tela informando que foi enviado um e-mail com a nova senha de acesso para o item que foi publicado publicado no buffer.

Link do código: https://github.com/jcelsocosta/race_condition/blob/main/producerconsumer/buffer/producerconsumer.go

Referência

  1. https://www.cs.utexas.edu/~EWD/transcriptions/EWD01xx/EWD123.html#4.1.%20Typical%20Uses%20of%20the%20General%20Semaphore.

Bibliografia

https://www.cin.ufpe.br/~cagf/if677/2015-2/slides/08_Concorrencia%20(Jorge).pdf

Top comments (1)

Collapse
 
tired_student profile image
Vinícius Sales Oliveira

Ótima explicação!