Obtém bloqueio exclusivo de leitura / gravação em um arquivo para atualizações atômicas

7

Eu quero ter um arquivo que é usado como um contador. O usuário A gravará e incrementará esse número, enquanto o Usuário B solicitará a leitura do arquivo. É possível que o Usuário A possa bloquear este arquivo para que ninguém possa ler ou escrever nele até que a gravação do Usuário A tenha terminado?

Eu olhei para flock , mas parece que não consigo funcionar como eu esperava.

flock -x -w 5 /dev/shm/counter.txt echo "4" >  /dev/shm/counter.txt && sleep 5

Se há uma maneira mais apropriada de obter esse arquivo de incremento semelhante ao de um átomo que seria ótimo ouvir também!

Meu objetivo é:

LOCK counter.txt; write to counter.txt;

enquanto ao mesmo tempo

Read counter.txt; realize it's locked so wait until that lock is finished.
    
por d-_-b 29.12.2013 / 19:44

3 respostas

8

O processamento de Bash do comando abaixo pode ser surpreendente:

flock -x -w 5 /dev/shm/counter.txt echo "4" >  /dev/shm/counter.txt && sleep 5

O Bash primeiro executa flock -x -w 5 /dev/shm/counter.txt echo "4" > /dev/shm/counter.txt e, se isso for concluído com êxito (liberando o bloqueio), ele será executado em sleep 5 . Assim, o bloqueio não é mantido pelos 5 segundos que se espera.

    
por 29.12.2013 / 21:09
12

Os bloqueios de arquivo não são obrigatórios 1 - ou seja, você não pode bloquear um arquivo para que outro processo não possa acessá-lo. Bloquear um arquivo significa que se um processo (nother) verifica para ver se foi bloqueado, ele saberá.

O objetivo de flock é fazer coisas como você deseja, mas você deve usar flock para cada tentativa de acesso . Tenha em mente que estes estão bloqueando chamadas; de man flock :

if the lock cannot be immediately acquired, flock waits until the lock is available

1. O que faz com que o recurso pareça inútil se você estiver usando-o para, por exemplo, segurança, mas esse não é o propósito dos bloqueios de arquivos - eles são para sincronização, que é o que você está fazendo. O usuário Leo apontou que pode haver uma implementação não padronizada do bloqueio obrigatório de arquivos no kernel do Linux ( veja esta discussão ), baseada em paralelos históricos de outros sistemas operacionais * nix. No entanto, isso parece ser apenas uma interface de nível C.

    
por 29.12.2013 / 21:06
1

Você poderia usar "sh -c command ..." para executar o comando shell inteiro, incluindo o redirecionamento de arquivos, com o bloqueio travado. Além disso, como você está usando o arquivo como um contador, você precisa manter o bloqueio continuamente enquanto faz a leitura e a gravação de volta. Então você gostaria de fazer algo assim para incrementar o contador e retornar seu novo valor:

flock --exclusive --wait 5 /dev/shm/counter.txt sh -c 'read count < /dev/shm/counter.txt ; echo $((count + 1)) > /dev/shm/counter.txt ; echo $((count + 1))'

Alterar os sinais de mais para sinais de menos deve diminuir o contador:

flock --exclusive --wait 5 /dev/shm/counter.txt sh -c 'read count < /dev/shm/counter.txt ; echo $((count - 1)) > /dev/shm/counter.txt ; echo $((count - 1))'

Espero que você inicialize o contador antes que qualquer contenção possa ocorrer. Portanto, não é necessário se preocupar com o bloqueio antecipado:

echo 0 > /dev/shm/counter.txt

Eu não acho que você precisaria estragar o valor do contador enquanto a contenção poderia ocorrer, mas, se você o fez, você deve fazer assim:

flock --exclusive --wait 5 /dev/shm/counter.txt sh -c 'echo 0 > /dev/shm/counter.txt'

Acho que você entende como fazer a leitura, mas incluo isso para ser completo:

flock --shared /dev/shm/counter.txt cat /dev/shm/counter.txt
    
por 18.11.2016 / 05:12