4 pontos por GN⁺ 2025-08-21 | Ainda não há comentários. | Compartilhar no WhatsApp
  • É levantada a crítica de que o livro The Art of Multiprocessor Programming não aborda o conceito de futex, o que é lamentável
  • O futex é um componente central da sincronização eficiente na programação paralela moderna, com desempenho superior aos locks tradicionais baseados em System V
  • O futex tem uma estrutura que separa a aquisição do lock das funções de espera/despertar, reduzindo chamadas de sistema desnecessárias e overhead
  • Estão incluídos exemplos e técnicas para implementar diretamente vários primitivos de concorrência com base em futex, como spinlock, mutex e lock recursivo
  • O autor aponta um distanciamento entre a academia e o mercado ao criticar que o livro não trata de metodologias modernas de sincronização essenciais para a prática de engenharia

Introdução

  • Phil Eaton iniciou um clube de leitura de The Art of Multiprocessor Programming, 2nd Edition
  • Embora esse livro seja considerado uma referência na área de programação paralela, o autor aponta a falta de utilidade prática do conteúdo
  • Em especial, critica o fato de que, apesar de dizer que se destina a alunos do último ano da graduação e da pós-graduação, ele não trata do futex, uma técnica central de sincronização

O que é futex — e por que isso importa

  • Futex é a abreviação de “fast user space mutex”, mas na prática é menos um mutex e mais um primitivo de sincronização com suporte do SO para implementações modernas de lock
  • No passado, a maioria dos locks era implementada com base em semáforos do System V IPC, o que trazia limitações de eficiência e escalabilidade
  • Com a introdução do futex no Linux em 2002, ele apresentou desempenho de 20 a 120 vezes superior aos locks do System V em ambientes com 1000 tarefas simultâneas
  • Outros sistemas operacionais, como Windows (2012) e macOS (2016), também adotaram mecanismos semelhantes
  • Hoje, os locks de bibliotecas de sistema amplamente usadas, como pthreads, utilizam futex

Como o futex funciona e o que o diferencia

  • Os semáforos tradicionais combinavam lock e espera, mas o futex separa a aquisição do lock do esperar/despertar
  • Isso reduz delays e chamadas de sistema desnecessárias, e ao liberar o lock, se for certo que não há threads esperando, nem é preciso entrar no kernel
  • A chamada de espera (wait) do futex faz com que a thread espere “somente quando o valor em um endereço de memória específico estiver no estado desejado”, além de oferecer suporte a timeout
  • A chamada de despertar (wake) do futex acorda a quantidade desejada de threads a partir de uma lista interna de espera associada a um endereço de memória específico
  • Como exige a verificação do valor real no endereço de memória, evita esperas desnecessárias quando o estado já mudou

Uso prático do futex — implementação direta

  • Como o futex é um primitivo de baixo nível, usam-se tipos atomic levando em conta questões de ordem das operações de memória do compilador e do hardware
  • No Linux, é preciso chamar diretamente a system call de futex via syscall; no macOS, usa-se a interface __ulock (mais recentemente, foi adicionada uma API mais simples)
  • Em termos básicos, uma espera de futex retorna 0 em caso de sucesso e um código de erro em caso de falha (como timeout)
  • Operações centrais baseadas em futex:
    • h4x0r_futex_wait_timespec() : espera se o valor esperado coincidir, com possibilidade de aplicar timeout
    • h4x0r_futex_wake() : acorda 1 ou todos os waiters

Exemplos práticos de implementação de mutex/spinlock/lock recursivo

Spinlock

  • A forma mais simples de lock, funcionando apenas com um único bit (atomic_fetch_or)
  • Fica em loop infinito (“spin”) até obter o lock, mas em cenários de alta contenção desperdiça CPU e tem problemas estruturais, como unlock incorreto e risco de deadlock em chamadas recursivas

Mutex híbrido (“unsafe” mutex)

  • Em geral, tenta primeiro com spinlock e, após certo número de falhas, muda para futex para fazer bloqueio eficiente
  • Se não houver waiters, evita chamadas de sistema desnecessárias, e para quem está esperando também é possível minimizar as chamadas de sistema de wake
  • Como não tem verificação rigorosa de ownership nem tratamento de recursão, recebe o nome de “unsafe”

Mutex com contador de waiters

  • Um bit representa o estado do lock, e o restante é usado para contabilizar o número de waiters, com o objetivo de reduzir chamadas de sistema de wake desnecessárias
  • Ainda não há tratamento de ownership nem de recursão

Mutex com gerenciamento de ownership

  • Com o valor de pthread_t, é possível rastrear claramente o dono do lock e seu estado, detectando problemas em unlocks incorretos ou uso recursivo
  • Aquisição, liberação e gerenciamento de waiters do lock são todos controlados com operações atômicas rigorosas

Lock recursivo

  • Adiciona um contador de profundidade (depth) por thread, permitindo que a mesma thread adquira o lock repetidamente
  • No unlock, o depth é reduzido e, quando chega a 0, ocorre o unlock real e o despertar das threads
  • Cada operação é implementada com operações atômicas e verificação rigorosa de ownership

Desafios restantes e a realidade da engenharia

  • Quando a thread dona do lock termina de forma anormal ou morre, o gerenciamento do lock exige gestão adicional, como uma lista de controle separada e callbacks de encerramento
  • Mesmo ao usar mutexes compartilhados entre processos, é preciso considerar de forma adicional como lidar com mudanças de estado
  • O RW lock do POSIX não define o comportamento de aninhamento recursivo, e isso varia entre implementações, o que dificulta garantir segurança na prática
  • O autor critica o fato de que o livro não inclui no currículo temas de concorrência realmente importantes na prática, como futex, locks recursivos e runtimes assíncronos

Conclusão

  • The Art of Multiprocessor Programming está inclinado demais à perspectiva histórica ou teórica e não traz adequadamente conhecimentos práticos modernos importantes de programação paralela
  • Se não tratar corretamente de componentes centrais de sincronização como o futex, que de fato operam nos sistemas reais, isso pode causar prejuízo prático aos futuros profissionais
  • O autor enfatiza a necessidade de refletir conceitos mais atuais e complementar o conteúdo com material mais prático

Referências

  • O exemplo completo de código pode ser visto no codeberg

Ainda não há comentários.

Ainda não há comentários.