DEV Community

Celso Costa
Celso Costa

Posted on

2

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

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (1)

Collapse
 
tired_student profile image
Vinícius Sales Oliveira

Ótima explicação!

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs