Pergunta

Outra questão sincronização ... Eu espero que vocês não se irrita;)

Suponha a seguinte situação: uma estrutura de dados central (muito grande, então eu realmente não quero fazê-lo imutável e copiá-lo em torno sempre que ocorre uma alteração que eu mesmo não quero manter várias cópias na memória.), vários segmentos leitor que o acesso que a estrutura de dados somente leitura e um fio escritor que mantém a estrutura de dados atualizado em segundo plano.

Actualmente, eu sincronizar todos os acessos à estrutura de dados, que funciona muito bem (sem efeitos de sincronização, sem impasses). O que eu não gosto sobre esta abordagem é que na maioria das vezes eu tenho um monte de tópicos leitor ativo e o fio escritor ativa somente de vez em quando. Agora é completamente desnecessário para os tópicos leitor de esperar por outros tópicos leitor ao fim. Eles poderiam facilmente acessar a estrutura de dados em paralelo, enquanto o fio escritor não está actualmente a escrever.

Existe uma agradável e elegante maneira de resolver este tipo de cenário?

EDIT: Muito obrigado pelas respostas e links! Deixe-me acrescentar apenas mais uma pergunta curta e relacionados: se o código executado dentro de seções críticas do leitor leva apenas um tempo muito curto (como apenas uma pesquisa tabela hash), é ainda vale a pena considerar implementação de uma das técnicas que descrevem ou é a serialização efeito dos bloqueios não tão ruim neste caso? Escalabilidade e desempenho são muito importantes. O que você acha?

EDIT 2: eu só olhei para uma implementação de um único escritor / leitores mulitple - bloqueio e essa implementação usa um monitor para sincronizar algum código no método WaitToRead. Isso não causa o mesmo efeito de serialização que eu queria evitar, em primeiro lugar? (Ainda assumindo que o código a ser sincronizados é curto e rápido)

Foi útil?

Solução

Há uma classe para esse fim no RTL (sysutils): TMultiReadExclusiveWriteSynchroniser

É muito fácil de usar. Você não precisa categorizar estritamente seus segmentos como leitor ou escritor. Basta ligar "BeginRead" ou "BeginWrite" em um thread para iniciar uma operação de thread-safe. Call "EndRead" ou "EndWrite" para terminar a operação.

Outras dicas

O que você está procurando (e que vartec descrito) é chamado Reader (s) -writer -Lock .

Você pode encontrar algumas notas detalhadas em resolver este problema em MSDN e um trecho de aplicações de programação para MS Windows .

Utilizar um bloqueio de leitor-gravador vai resolver o problema. leitores múltiplos podem acessar um banco de dados e um escritor recebe um bloqueio de uma vez todos os leitores são leitura final.

No entanto, isso pode fazer com que o escritor nunca tem acesso à fonte, pois há sempre novos leitores que querem ter acesso. Isso pode ser resolvido através do bloqueio de novos leitores quando um escritor quer acesso: o escritor tem uma prioridade maior. O escritor tem acesso uma vez que todos os leitores sobre a fonte de terminar de ler.

Sempre escritor quer o acesso, você enfileirar leitores de entrada (tê-los esperar Condição), espera para os leitores ativos para terminar, gravação e quando terminou deixar o acesso com leitores enfileirado.

Ninguém pode realmente responder a sua pergunta se a serialização afetará o desempenho em sua aplicação muito -. Você tem ao perfil que para si mesmo, e os resultados vão depender muito do número de threads, núcleos e a carga de trabalho específica

Note no entanto que o uso de sincronização mais inteligente do que as seções críticas, como o leitor-escritor-lock, pode introduzir problemas de fome que podem ser difíceis de depurar e correção. Você realmente precisa de olhar duro em se o aumento da taxa de transferência supera os problemas potenciais. Note também que não pode realmente ser um aumento na taxa de transferência, especialmente se o código bloqueado é muito curto e rápido. Há um bom artigo de Jeffrey Richter que realmente contém esta citação:

Desempenho Mesmo quando não há disputa por um ReaderWriterLock, seu desempenho é muito lento. Por exemplo, uma chamada para o seu método AcquireReaderLock leva cerca de cinco vezes mais tempo para executar do que uma chamada ao método Enter do Monitor.

Isto é para .NET é claro, mas os princípios subjacentes se aplicam também.

O bloqueio de leitor-escritor é o que você precisa. Tutorial tem uma descrição, mas eu tenho certeza que alguém estava adicionando isso como padrão para Delphi. Pode valer a pena D2009 verificação não o tenha feito.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top