Implementação de uma fila sem bloqueios
Acompanhe o design de uma fila sem bloqueios para um produtor e um consumidor
Implementação de uma fila sem bloqueios é uma aula grátis de C++ Academy no CoddyKit. Esta é a aula 3 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C++ Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C++ Academy inclui 4 aulas no total.
Por que usar filas sem bloqueio?
Filas com mutexes podem se tornar gargalos sob alta contenção. Uma fila sem bloqueio permite que produtores e consumidores progridam simultaneamente.
SPSC versus MPMC
Duas variantes:
- SPSC — um produtor, um consumidor (mais simples e rápida)
- MPMC — vários produtores, vários consumidores (mais geral)
SPSC é a escolha natural quando você controla as duas extremidades.
Esboço de um buffer circular SPSC
Um buffer circular com dois índices: início (consumidor) e fim (produtor). Cada lado atualiza seu próprio índice.
template <typename T, size_t N>
class SpscQueue {
T buffer_[N];
std::atomic<size_t> head_{0};
std::atomic<size_t> tail_{0};
public:
bool push(const T& v);
bool pop(T& v);
};Inserção em SPSC
O produtor verifica os espaços livres, escreve e depois publica atualizando o fim.
bool push(const T& v) {
const size_t t = tail_.load(std::memory_order_relaxed);
const size_t next = (t + 1) % N;
if (next == head_.load(std::memory_order_acquire))
return false; // full
buffer_[t] = v;
tail_.store(next, std::memory_order_release);
return true;
}Remoção em SPSC
O consumidor verifica se há dados, lê e depois publica atualizando o início.
bool pop(T& v) {
const size_t h = head_.load(std::memory_order_relaxed);
if (h == tail_.load(std::memory_order_acquire))
return false; // empty
v = buffer_[h];
head_.store((h + 1) % N, std::memory_order_release);
return true;
}Emparelhamento da ordem de memória
O armazenamento com semântica de liberação em tail sincroniza com o carregamento com semântica de aquisição em tail no consumidor (e vice-versa). Sem a ordenação correta, as escritas dos dados poderiam ser reordenadas para depois da atualização do índice.
Preenchimento de linhas de cache
Para evitar o compartilhamento falso, coloque head_ e tail_ em linhas de cache separadas (normalmente a 64 bytes de distância). Use alignas.
alignas(64) std::atomic<size_t> head_{0};
alignas(64) std::atomic<size_t> tail_{0};MPMC: muito mais difícil
Vários produtores ou consumidores exigem coordenação adicional — normalmente com laços de CAS em índices compartilhados. Existem muitos projetos (fila de Vyukov, fila MS, baseada em ponteiros de risco).
Boost.Lockfree
É difícil criar filas sem bloqueios com qualidade de produção. Use Boost.Lockfree ou ProducerConsumerQueue da Folly em vez de criar sua própria implementação.
Compromissos
Filas sem bloqueios:
- Maior vazão sob contenção
- Latência limitada (sem esperar por um bloqueio)
- Muito mais difíceis de escrever e depurar
- Erros de ordenação de memória são silenciosos e difíceis de localizar
Teste de código sem bloqueios
Use ThreadSanitizer (-fsanitize=thread) para detectar condições de corrida nos dados. Use testes de estresse com inserções aleatórias de Sleep para revelar erros de ordenação.
Quando a exclusão mútua é suficiente
A maioria dos aplicativos não precisa de filas sem bloqueios. Primeiro faça medições — uma fila protegida por exclusão mútua e bem implementada frequentemente apresenta desempenho adequado, especialmente com processamento em lotes.
Verificação rápida
O que é compartilhamento falso e por que preencher head_ e tail_?
Recapitulação
Uma fila SPSC sem bloqueios usa um buffer circular com o fim pertencente ao produtor e o início pertencente ao consumidor. Use ordenação de aquisição/liberação e preencha os índices para separá-los em linhas de cache distintas. Para MPMC, prefira uma biblioteca testada.
Perguntas Frequentes
A aula “Implementação de uma fila sem bloqueios” é grátis?
Sim — o texto completo de “Implementação de uma fila sem bloqueios” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C++ Academy, atualize para CoddyKit PRO. O curso de C++ Academy inclui 4 aulas no total.
O que vou aprender em “Implementação de uma fila sem bloqueios”?
Acompanhe o design de uma fila sem bloqueios para um produtor e um consumidor Você pratica C++ Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar C++ Academy?
Nenhuma experiência prévia é necessária. C++ Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 3 de 4.
Quanto tempo leva a aula “Implementação de uma fila sem bloqueios”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de C++ Academy?
Sim. Cada aula de C++ Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- std::atomic e ordens de memória
- Padrões de compare-and-swap: CAS
- Implementação de uma fila sem bloqueios
- Ponteiros de perigo e o problema ABA