Certamente, muitos ouviram, mas alguém se encontrou na prática, palavras como impasses e condições de corrida. Esses conceitos são classificados como erros no uso da simultaneidade. Se eu fizer uma pergunta sobre o que é um impasse, é muito provável que você comece a desenhar uma imagem clássica de impasse ou sua representação em pseudo-código sem qualquer dúvida. Algo assim:

Recebemos essas informações no instituto, que podem ser encontradas em livros e artigos na Internet. Esse impasse usando, por exemplo, dois mutexes, em toda a sua glória, pode ser encontrado no código. Mas, na maioria dos casos, nem tudo é tão simples, e nem todos podem ver o padrão de erro clássico no código, se ele não for apresentado da forma usual.

Considere uma classe na qual estamos interessados nos métodos StartUpdate, CheckAndUpdate e Stop, C ++ é usado, o código é o mais simples possível:
std::recursive_mutex m_mutex; Future m_future; void Stop() { std::unique_lock scoped_lock(m_mutex); m_future.Wait();
No que você deve prestar atenção no código apresentado:
- mutex recursivo é usado. A captura repetida de um mutex recursivo não leva à expectativa apenas se essa captura ocorrer no mesmo encadeamento. Nesse caso, o número de isenções mutex deve corresponder ao número de capturas. Se tentarmos capturar um mutex recursivo que já está capturado em outro encadeamento, o encadeamento entrará no modo de espera.
- A função Future :: Schedule é iniciada (em n milissegundos) em um thread separado que o retorno de chamada passou para ele
Agora analisamos todas as informações recebidas e compomos uma imagem:

Considerando os dois fatos apresentados acima, não é difícil concluir que uma tentativa de capturar um mutex recursivo em uma das funções levará à expectativa de liberação do mutex se ele já tiver sido capturado em outra função, pois o retorno de chamada CheckAndUpdate sempre é executado em um thread separado.
À primeira vista, não há nada suspeito em relação ao impasse. Mas, para ser mais próximo, tudo se resume à nossa imagem clássica. Quando o objeto funcional começa a executar, capturamos implicitamente o recurso m_future, o retorno de chamada diretamente
associado ao m_future:
A sequência de ações que levam ao impasse é a seguinte:- Está planejado executar o CheckAndUpdate, mas o retorno de chamada não inicia imediatamente, após n milissegundos.
- O método Stop é chamado e, em seguida, é iniciado: tentamos capturar o mutex - o recurso é um capturado, começamos a esperar que m_future seja concluído - o objeto ainda não foi chamado, estamos aguardando.
- A execução do CheckAndUpdate começa: tentamos capturar o mutex - não podemos, o recurso já está capturado por outro encadeamento, estamos aguardando liberação.
Isso é tudo: o encadeamento que faz a chamada Stop aguarda a conclusão do CheckAndUpdate, e o outro encadeamento, por sua vez, não pode continuar trabalhando até pegar o mutex que já foi capturado pelo encadeamento mencionado anteriormente. É um impasse clássico. Metade do trabalho está concluído - a causa do problema foi descoberta.
Agora um pouco sobre como corrigi-lo.Abordagem 1O procedimento para capturar recursos deve ser o mesmo, para evitar conflitos. Ou seja, você precisa ver se é possível alterar a ordem de captura de recursos no método Stop. Como aqui o caso de impasse não é totalmente óbvio e não há captura explícita do recurso m_future no CheckAndUpdate, decidimos pensar em outra solução para evitar o retorno de erro no futuro.
Abordagem 2- Verifique se você pode optar por não usar o mutex em CheckAndUpdate.
- Como usamos o mecanismo de sincronização, restringimos o acesso a alguns recursos. Talvez seja o suficiente para você refazer esses recursos em atômicos (como tínhamos), cujo acesso já é seguro para threads.
- Descobriu-se que as variáveis, cujo acesso era limitado, podem ser facilmente convertidas em atômicas, portanto o mutex mencionado é excluído com sucesso.
Aqui está um exemplo tão simples com um impasse não óbvio que se reduz facilmente ao padrão desse erro. Finalmente, desejo que você escreva um código confiável e seguro para threads!