Tenho um aplicativo multithread que precisa ler alguns dados com frequência e, ocasionalmente, esses dados são atualizados. No momento, um mutex mantém o acesso a esses dados seguro, mas é caro porque eu gostaria que vários threads pudessem ler simultaneamente, e apenas bloqueá-los quando uma atualização for necessária (o thread de atualização pode esperar que os outros threads terminem) .
Acho que é isso que boost::shared_mutex
se deve fazer, mas não tenho certeza de como usá-lo e não encontrei um exemplo claro.
Alguém tem um exemplo simples que eu possa usar para começar?
c++
multithreading
boost
mutex
boost-thread
kevin42
fonte
fonte
Respostas:
Parece que você faria algo assim:
fonte
1800 INFORMAÇÕES está mais ou menos correto, mas há alguns problemas que eu gostaria de corrigir.
Observe também que, ao contrário de um shared_lock, apenas uma única thread pode adquirir um upgrade_lock por vez, mesmo quando não está atualizado (o que achei estranho quando o encontrei). Portanto, se todos os seus leitores são escritores condicionais, você precisa encontrar outra solução.
fonte
boost::unique_lock< boost::shared_mutex > lock(lock);
lerboost::unique_lock< boost::shared_mutex > lock(
_access);
?Desde C ++ 17 (VS2015), você pode usar o padrão para bloqueios de leitura e gravação:
Para versões anteriores, você pode usar boost com a mesma sintaxe:
fonte
typedef boost::unique_lock< Lock > WriteLock; typedef boost::shared_lock< Lock > ReadLock;
.Apenas para adicionar mais algumas informações empíricas, estive investigando toda a questão de bloqueios atualizáveis e Exemplo para boost shared_mutex (várias leituras / uma gravação)? é uma boa resposta adicionando a informação importante de que apenas um thread pode ter um upgrade_lock mesmo se não for atualizado, o que é importante porque significa que você não pode atualizar de um bloqueio compartilhado para um bloqueio exclusivo sem liberar o bloqueio compartilhado primeiro. (Isso foi discutido em outro lugar, mas o tópico mais interessante está aqui http://thread.gmane.org/gmane.comp.lib.boost.devel/214394 )
No entanto, encontrei uma diferença importante (não documentada) entre um thread aguardando uma atualização para um bloqueio (ou seja, precisa esperar que todos os leitores liberem o bloqueio compartilhado) e um bloqueio de gravador aguardando a mesma coisa (ou seja, um unique_lock).
O thread que está esperando por um unique_lock no shared_mutex bloqueia quaisquer novos leitores que entrem, eles têm que esperar pela solicitação dos escritores. Isso garante que os leitores não deixem os escritores famintos (no entanto, acredito que os escritores podem matar os leitores de fome).
O encadeamento que está aguardando a atualização de um upgradeable_lock permite que outros encadeamentos obtenham um bloqueio compartilhado, portanto, este encadeamento pode ser interrompido se os leitores forem muito frequentes.
Esta é uma questão importante a se considerar e provavelmente deve ser documentada.
fonte
Terekhov algorithm
garante que em1.
, o escritor não pode morrer de fome os leitores. Veja isso . Mas2.
é verdade. Um upgrade_lock não garante justiça. Veja isso .Use um semáforo com uma contagem igual ao número de leitores. Deixe cada leitor contar uma vez no semáforo para ler, de forma que todos possam ler ao mesmo tempo. Em seguida, deixe o escritor fazer TODAS as contagens do semáforo antes de escrever. Isso faz com que o gravador espere que todas as leituras terminem e bloqueie as leituras durante a gravação.
fonte
Ótima resposta de Jim Morris, descobri isso e demorei um pouco para descobrir. Aqui está um código simples que mostra que, após enviar uma "solicitação" para um impulso unique_lock (versão 1.54), bloqueia todas as solicitações shared_lock. Isso é muito interessante, pois me parece que escolher entre unique_lock e upgradeeable_lock permite se queremos prioridade de gravação ou nenhuma prioridade.
Também (1) na postagem de Jim Morris parece contradizer isso: Boost shared_lock. Leia preferido?
fonte