Atualização editorial em : fontes e exemplos revistos; a data da publicação original foi preservada.
Uma fila com mutex e condition_variable é um exemplo de coordenação entre threads, não evidência de baixa latência. Antes de discutir desempenho, o programa precisa definir o que acontece quando não há itens e como os consumidores terminam.
As regras de sincronização relevantes
As C++ Core Guidelines recomendam esperar por uma condição verificável (CP.42), limitar a duração de seções críticas (CP.43) e não sustentar afirmações de desempenho sem medições (Per.6). No exemplo abaixo, a condição é haver um item ou a fila ter sido fechada. O processamento do item fica fora do bloqueio da fila.
Fila finita no uso, com encerramento explícito
A classe didática aceita inteiros. enviar retorna falso depois do fechamento. receber aguarda quando a fila está vazia e aberta; depois de fechada, entrega os itens restantes e só então retorna std::nullopt. Fechar novamente é permitido. O arquivo fila.hpp contém a implementação completa:
#pragma once
#include <condition_variable>
#include <mutex>
#include <optional>
#include <queue>
class Fila {
std::mutex mutex_;
std::condition_variable pronta_;
std::queue<int> itens_;
bool fechada_ = false;
public:
bool enviar(int valor) {
{
std::lock_guard<std::mutex> trava(mutex_);
if (fechada_) return false;
itens_.push(valor);
}
pronta_.notify_one();
return true;
}
std::optional<int> receber() {
std::unique_lock<std::mutex> trava(mutex_);
pronta_.wait(trava, [this] { return fechada_ || !itens_.empty(); });
if (itens_.empty()) return std::nullopt;
const int valor = itens_.front();
itens_.pop();
return valor;
}
void fechar() {
{
std::lock_guard<std::mutex> trava(mutex_);
fechada_ = true;
}
pronta_.notify_all();
}
};
O consumidor consulta o estado sob o mesmo mutex que protege a inserção e o fechamento. A notificação não é tratada como um item: ao acordar, a condição é conferida novamente. notify_all no fechamento permite que mais de um consumidor observe o encerramento.
O programa main.cpp envia três valores, fecha a fila e aguarda a thread antes de destruir os objetos compartilhados. A impressão ocorre depois que receber libera sua trava:
#include "fila.hpp"
#include <iostream>
#include <thread>
int main() {
Fila fila;
std::thread consumidor([&] {
while (auto valor = fila.receber()) {
std::cout << *valor << '\n';
}
});
try {
for (int valor = 1; valor <= 3; ++valor) fila.enviar(valor);
} catch (...) {
fila.fechar();
consumidor.join();
throw;
}
fila.fechar();
consumidor.join();
}
Em um ambiente com GCC e suporte a C++17, salve os arquivos no mesmo diretório e compile a partir dele:
g++ -std=c++17 -Wall -Wextra -Werror -pedantic -pthread main.cpp -o fila
./fila
g++ -std=c++17 -Wall -Wextra -Werror -pedantic -pthread test.cpp -o teste
./teste
A saída do programa é 1, 2 e 3, uma linha por valor. O arquivo test.cpp verifica ordem FIFO, drenagem após fechar, rejeição de novos envios, fim de consumidores e entrega de 10.000 inteiros sem perda ou duplicação usando dois consumidores. O job cpp-example compila o programa e repete os testes no CI. Isso verifica comportamento funcional nos cenários executados, não todas as possíveis intercalações de threads.
Por que o exemplo não comprova baixa latência
Não há benchmark de latência ou garantia de tempo real. A fila não limita memória, não oferece cancelamento nem controle de pressão e deve existir até todos os usuários terminarem. Não há promessa de justiça entre consumidores. A referência anterior era uma vaga de emprego sem URL recuperável; ela não sustentava uma experiência pessoal ou resultados de desempenho. A revisão substitui essa narrativa por um exemplo funcional limitado, sem atribuir testes profissionais a Anderson Damasio.