Em um aplicativo C ++ multithread, preciso de um mutex para proteger um booleano simples?
-
03-07-2019 - |
Pergunta
Eu tenho um aplicativo C ++ multithread que faz renderização em 3D com a biblioteca OpenSceneGraph. Estou planejando iniciar o loop de renderização da OSG como um thread separado usando o boost :: threads, passando uma estrutura de dados contendo estado compartilhado para o thread. Estou tentando evitar algo muito pesado (como mutexes) para sincronização, pois o loop de renderização precisa ser bem apertado, e o próprio OSG tenta evitar ter que travar. A maior parte do estado compartilhado é definido antes do início do tópico e nunca alterado. Eu tenho alguns dados que precisam ser alterados, que estou planejando dobrar duas vezes. No entanto, tenho um simples booleano para sinalizar o fio para suspender a renderização e depois retomar a renderização e outra para matá -la. Nos dois casos, o encadeamento do aplicativo define o bool e o thread de renderização apenas o lê. Preciso sincronizar o acesso a essas bools? Até onde eu sei, a pior coisa que poderia acontecer é o loop de renderização continua para um quadro extra antes de suspender ou desistir.
Solução
Em C ++ 11 e posterior, que possui simultaneidade definida por padrões, use std::atomic<bool>
para esse fim. A partir de http://en.cppreference.com/w/cpp/atomic/atomic:
Se um thread gravar em um objeto atômico enquanto outro thread lê, o comportamento será bem definido (consulte o modelo de memória para obter detalhes nas corridas de dados).
A seguinte resposta antiga pode ter sido verdadeira em algum momento no passado com alguns compiladores e alguns ambientes operacionais, mas não deve ser invocado hoje:
Você está certo, neste caso, você não precisará sincronizar os bools. Você deve declará -los volatile
No entanto, para garantir que o compilador realmente os leia da memória a cada vez, em vez de armazenar em cache a leitura anterior em um thread (essa é uma explicação simplificada, mas deve fazer para esse fim).
A pergunta seguinte tem mais informações sobre isso: Tópico C ++, dados compartilhados
Outras dicas
Por que não simplesmente usar um variável interligada?
Quanto ao C ++ 11 e posteriormente, finalmente é consciente de threads e afirma claramente que modificar um bool (ou outra variável não atômica) em um encadeamento e acessar-o ao mesmo tempo em outro é um comportamento indefinido. No seu caso usando std::atomic<bool>
deve ser suficiente para corrigir seu programa, economizando você de usar bloqueios.
Não use volatile
. Não tem nada a ver com threads. Para mais discussões, veja Posso ler uma variável bool em um thread sem mutex?
Eu não acho que você precisar Um mutex totalmente completo aqui - embora o thread de renderização precise esperar o estado 'suspenso' se você não estiver usando um objeto de sincronização que suporta uma espera primitiva.
Você deve usar o uso das várias primitivas de troca entrelaçadas (interlockedExchange no Windows). Não porque a leitura/grava do bool não seja atômica, mas para garantir que não haja comportamentos estranhos, o compilador reordenando a memória acessos em um único encadeamento.
Este tópico tem um pouco mais de informação e discussão sobre segurança, especialmente para tipos de dados simples:
Como posso criar um padrão de singleton seguro para threads no Windows?