Técnicas genéricas de bloqueio de recursos compartilhados - é reunir a solução?

2

Eu preciso implementar um esquema de bloqueio para que vários processos possam compartilhar um conjunto de recursos, enquanto um processo "especial" pode obter acesso exclusivo a esse conjunto de recursos.

São processos em lote: no início de cada transação, proponho adquirir o bloqueio apropriado e liberá-lo no final, ad infinitum.

flock tem a semântica que eu preciso (LOCK_SH, LOCK_EX, LOCK_UN). Eu experimentei usando o Perl Flock.pm e um arquivo fictício cuja única finalidade é ser flock 'contra. Fiquei um pouco surpreso com o quão lento foi, e não era evidente a partir do 'topo', onde o tempo foi gasto. (Não estava ligado à CPU, mesmo que o loop sendo executado consistisse em nada além de LOCK_SH e LOCK_UN). Eu não quero ser culpado de otimização prematura, mas eu queria saber se flock é o método padrão para gerenciando acesso compartilhado e exclusivo a um recurso compartilhado no * nix, mesmo quando o recurso compartilhado não é um arquivo real, ou se havia outro recurso que eu não conheço.

UPDATE : @msw adivinhou corretamente que eu tinha (inadvertidamente) trancado em um arquivo NFS ao invés de um local. Usando um arquivo local completamente esclareceu o desempenho que eu estava vendo. Estou deixando a questão em aberto para saber mais sobre se o "bloqueio de arquivo" é realmente o melhor caminho para essa classe de problemas.

    
por Chap 18.12.2014 / 23:50

1 resposta

6

O Unix tem uma infinidade de sistemas de bloqueio. O que você encontrou é chamado de bloqueio de arquivo BSD, mas existem outros métodos de bloqueio de arquivos. Além disso, você também tem semáforos , mutexes e muito mais.

Quanto à sua pergunta direta, sim, é um jeito perfeito de ir. Não se preocupe com o tempo que leva. O bloqueio é uma atividade de alta sobrecarga, por sua própria natureza. É por isso que tanto esforço é dedicado à criação de mecanismos sem bloqueios .

A única coisa que me incomoda sobre o seu plano é o arquivo fictício que você tem que criar. Pode haver uma maneira mais simples de atingir seu objetivo desejado: mkdir(2) . A chamada é atômica e você recebe um erro quando o diretório já existe. Por contraste, open(2) é apenas atômico com O_EXCL , que não está disponível em todos os lugares. Quando disponível, pode não funcionar como esperado, seja porque você está usando o NFSv2 ou porque você não ativou o Daemon de bloqueio de arquivos NFS .

Uma vez que a abordagem mkdir é agradável, você pode fazer isso em scripts de shell, via mkdir(1) . Vejo que você está usando o Perl, mas, nesse caso, é uma função incorporada, em vez de um módulo externo.

Outra coisa interessante é que ele funcionará no NFS sem nenhuma ajuda especial. Você não pode criar um diretório duas vezes.

O único problema com a abordagem mkdir() é que não há como esperar que um diretório existente desapareça. Ou seja, não é uma operação de bloqueio de bloqueio. Sugiro que você o envolva com um temporizador, para que os processos que competem pelo bloqueio passem a maior parte do tempo dormindo. Sugiro que você faça com que cada processo espere um período aleatório de janela. Por exemplo, entre 100 e 200 ms, via usleep(3) . Isso criaria uma forma de spinlock .

    
por 19.12.2014 / 00:36

Tags