Qual é o melhor mecanismo de bloqueio do kernel linux para um cenário específico
-
06-09-2019 - |
Pergunta
Eu preciso para resolver um problema de bloqueio para este cenário:
- Um sistema multi CPU.
- Todos da CPU usar um recurso comum (software).
- Leia apenas o acesso ao recurso é muito comum. (O processamento de pacotes de rede de entrada)
- acesso de escrita é muito menos frequente. (Praticamente configuração altera apenas).
Atualmente eu uso o mecanismo (spinlocks) read_lock_bh
write_lock_bh
.
O problema é que quanto mais da CPU, mais eu recebo travamentos macios em um contexto escritor.
Eu li o capítulo simultaneidade em este livro , Mas não conseguia entender se o leitor ou o escritor terá prioridade quando usando bloqueios de rotação.
Assim, as perguntas são:
- Será que o Linux spinlock prioridade mecanismo de dar ao leitor / escritor / nenhum deles?
- Existe um mecanismo melhor que eu posso usar, a fim de evitar os travamentos macios no meu cenário, ou talvez uma maneira para eu dar prioridade ao escritor sempre que ele tenta obter o bloqueio, enquanto estiver usando minha solução atual?
Obrigado, Nir
Solução
Aqui está uma citação direta de Drivers de dispositivos essenciais do Linux que pode ser o que você está procurando. Parece que a parte lidar com RCU no final pode ser o que você está em interessado.
Leitor-Writer Locks
Outro mecanismo de regulação de concorrência especializado é uma variante leitor-gravador de spinlocks. Se o uso de um seção crítica é tal que segmentos separados quer ler ou escrever para uma estrutura de dados compartilhada, mas não faça tanto, esses bloqueios são uma escolha natural. Vários segmentos de leitor são permitidos dentro de uma região crítica simultaneamente. spinlocks Reader são definidos da seguinte forma:
rwlock_t myrwlock = RW_LOCK_UNLOCKED;
read_lock(&myrwlock); /* Acquire reader lock */
/* ... Critical Region ... */
read_unlock(&myrwlock); /* Release lock */
No entanto, se um fio escritor entra em uma seção crítica, outros segmentos leitor ou gravador não são permitidos dentro. Usar spinlocks escritor, você escreveria o seguinte:
rwlock_t myrwlock = RW_LOCK_UNLOCKED;
write_lock(&myrwlock); /* Acquire writer lock */
/* ... Critical Region ... */
write_unlock(&myrwlock); /* Release lock */
Olhe para o IPX roteamento código presente em net/ipx/ipx_route.c
para um exemplo da vida real de um spinlock leitor-gravador. UMA
bloqueio de leitor-escritor chamado ipx_routes_lock
protege IPX roteamento tabela do acesso simultâneo a. Tópicos
essa necessidade de olhar para cima da tabela de roteamento para encaminhar pacotes solicitar bloqueios de leitor. Tópicos que precisam adicionar ou
entradas Excluir no roteamento fechaduras escritor mesa adquirir. Isso melhora o desempenho porque há normalmente
muito mais instâncias de roteamento pesquisas de tabela de roteamento atualizações da tabela.
Como spinlocks regulares, bloqueios de leitor-escritor também correspondente IRQ variantes, ou seja, read_lock_irqsave()
,
read_lock_irqrestore()
, write_lock_irqsave()
e write_lock_irqrestore()
. A semântica destes
funções são semelhantes aos de spinlocks regulares.
fechaduras seqüência ou seqlocks, introduzido no kernel 2.6, são bloqueios de leitor-escritor onde os escritores são favorecidos sobre
leitores. Isto é útil se as operações de escrita em uma variável superam em muito ler acessos. Um exemplo é a
variável jiffies_64
discutido anteriormente neste capítulo. tópicos escritor não espere para os leitores que possam estar dentro
uma secção crítica. Devido a isso, tópicos leitor pode descobrir que a sua entrada dentro de uma seção crítica falhou
e pode precisar de repetir:
u64 get_jiffies_64(void) /* Defined in kernel/time.c */
{
unsigned long seq;
u64 ret;
do {
seq = read_seqbegin(&xtime_lock);
ret = jiffies_64;
} while (read_seqretry(&xtime_lock, seq));
return ret;
}
Writers proteger regiões críticas usando write_seqlock()
e write_sequnlock()
.
O kernel 2.6 introduziu um outro mecanismo chamado Leia-Copy Update (RCU) , que o rendimento melhorou
desempenho quando os leitores escritores superam em muito . A idéia básica é que tópicos leitor pode executar sem
de bloqueio. tópicos escritor são mais complexas. Eles executam operações de atualização em uma cópia da estrutura de dados e
substituir o ponteiro que os leitores vêem. A cópia original é mantida até que a mudança de contexto próxima em todas as CPUs para
garantir a conclusão de todas as operações de leitura em curso. Esteja ciente de que o uso de RCU é mais envolvido do que usando o
primitivas discutido até agora e deve ser usado somente se tiver certeza de que é a ferramenta certa para o trabalho. dados RCU
estruturas e funções de interface são definidos em include/linux/rcupdate.h
. Há ampla documentação em
Documentation/RCU/*
.
Para um exemplo de uso RCU , olhada fs/dcache.c
. No Linux, cada arquivo está associada a entrada de diretório
dados de informação (armazenado em uma estrutura chamada dentry), informações de metadados (armazenado em um inodo), e reais
(Armazenados nos blocos de dados). Cada vez que você operar em um arquivo, os componentes no caminho do arquivo são analisados, eo
dentries correspondentes são obtidos. Os dentries são mantidos em cache em uma estrutura de dados chamada dcache, a
acelerar as operações futuras. A qualquer momento, o número de dcache pesquisas é muito mais do que dcache atualizações, então
referências ao dcache são protegidos utilizando primitivas RCU.
Outras dicas
Não é este o tipo de caso de uso RCU é projetado para lidar? Consulte http://lwn.net/Articles/262464/ para uma boa escrever em cima dele de uso .
Se o trabalho que você faz, mantendo o bloqueio é pequeno você pode tentar um mutex normal, não leitor-gravador. É mais eficiente.