Possível bug em std::shared_mutex no Windows
- Uma equipe de software encontrou um comportamento inesperado relacionado a
std::shared_mutex no Windows.
- Esse problema ocorre apenas no MSVC e não aparece no MinGW nem em outras plataformas.
- Quando a thread principal adquire um lock exclusivo e depois várias threads filhas tentam adquirir locks compartilhados, ocorre um "deadlock" em cerca de 1 a cada 1000 vezes.
- Quando o deadlock acontece, exatamente 1 thread filha consegue adquirir o lock compartilhado com sucesso, e as demais threads filhas ficam bloqueadas para sempre em
lock_shared().
- Esse problema foi observado com
std::shared_mutex, std::shared_lock/std::unique_lock e também ao chamar diretamente as funções de SRW.
Exemplo de código e reprodução do bug
- Foi fornecido um código simples capaz de reproduzir o problema.
- O código repete o processo em que a thread principal adquire um lock exclusivo, várias threads filhas adquirem locks compartilhados e depois os liberam.
- Esse código mostra um bug relacionado a
std::shared_mutex apenas na implementação do Windows com MSVC.
Opinião dos especialistas
- Um desenvolvedor da STL comentou que isso parece ser um bug da API do Windows.
- Houve discussão sobre os passos adequados para relatar o bug, e o desenvolvedor da STL fez o reporte internamente.
- Outros usuários investigaram o problema em detalhes e contribuíram para isolar um bug específico na implementação de
SRWLock.
Opinião do GN⁺
- Este artigo traz informações especialmente importantes para desenvolvedores C++. O possível bug em
std::shared_mutex pode afetar os mecanismos de sincronização de aplicações multithread.
- Se o bug for confirmado, isso pode afetar a confiança na implementação da biblioteca padrão de C++. Os desenvolvedores precisam estar cientes desse tipo de problema e talvez considerar mecanismos alternativos de sincronização.
- Esse problema pode ser especialmente importante em sistemas de alto desempenho ou de tempo real, nos quais um deadlock pode ter consequências críticas.
- Antes de adotar essa tecnologia, os desenvolvedores devem realizar testes extensivos na plataforma e no compilador em uso para verificar se esse tipo de bug não está presente.
- Para lidar com esse tipo de problema, os desenvolvedores podem considerar bibliotecas alternativas de sincronização, como a Boost. Como a Boost é amplamente testada e usada em muitas plataformas, ela pode oferecer uma alternativa confiável para esse tipo de situação.
1 comentários
Comentários do Hacker News
Um usuário se pergunta por que um problema tão básico não foi descoberto por tanto tempo e menciona uma resposta convincente fornecida por outro usuário. Ele aponta que uma thread que tenta adquirir o bloqueio em modo compartilhado pode, por engano, obter o bloqueio em modo exclusivo. Isso ocorre por causa da sobreposição de operações atômicas de teste e definição de bits quando a thread que adquire em modo compartilhado e a thread que libera em modo exclusivo são executadas ao mesmo tempo.
Outro usuário diz que não se surpreende com bugs sutis em bloqueios Reader/Writer e compartilha sua experiência de ter trabalhado em uma implementação interna baseada em Win32 antes do C++11 e do
std::shared_mutex. Ele afirma que, por causa de experiências ruins com bloqueios compartilhados, tenta evitá-los a menos que sejam absolutamente necessários.Um usuário aponta que o título é enganoso e explica que o bug real está no bloqueio slim reader/writer (SRW) da Windows API, tendo sido descoberto porque
std::shared_mutexfoi implementado usando o bloqueio SRW. Um funcionário da Microsoft confirma que o bug foi reportado internamente à equipe da Windows API.Um usuário se pergunta se o mesmo problema ocorre na implementação do WINE e diz que também gostaria de testar em sua própria instalação personalizada do XP. Nessa instalação, ele adicionou várias extensões, incluindo a API SRW, e afirma ter aplicado um patch no kernel para corrigir uma condição de corrida que causava deadlock na API de keyed event baseada na implementação de SRW.
Foi apontado que há um bug no programa. Ele mistura variáveis não atômicas e atômicas no loop de verificação com
yield(), e variáveis não atômicas não garantem coerência de cache entre threads. Por causa disso, o loop pode executar para sempre.Um usuário comenta que esse bug remonta à versão Vista de 2008 e expressa surpresa pelo fato de ninguém tê-lo descoberto por tanto tempo. Ele menciona que, no uso comum de
rwlock, podem ocorrer casos aleatórios em que o bloqueio compartilhado não é adquirido, mas sem deadlock.Um usuário diz que é muito difícil reportar bugs da Windows API e critica o fato de orientarem as pessoas a usar o Feedback Hub, o que quase não funciona. Ele relata ter reportado um bug em que o
SRWLOCKpode entrar em deadlock quando várias threads de leitura tentam adquirir juntas a posse compartilhada depois que o dono exclusivo libera a posse.Um usuário relembra que, no passado, ao comprar produtos da MS, era possível receber incidentes de suporte, e que, quando um bug real era encontrado, o incidente de suporte era reembolsado. Ele comenta que isso era útil para desenvolvedores e também um bom sistema para a MS, pois fornecia feedback para encontrar problemas reais e melhorar a documentação. Ele se pergunta se esse programa ainda existe.
Por fim, um usuário expressa frustração com a dificuldade de reportar bugs da Windows API.