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

9

Quero ter um arquivo usado como 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 esse arquivo para que ninguém possa ler ou gravar nele até a gravação do Usuário A terminar?

Eu examinei, flockmas não consigo fazê-lo funcionar como eu esperava.

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

Se houver uma maneira mais apropriada de obter esse arquivo de incremento atômico, também seria ótimo ouvir isso!

Minha meta é:

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.
d -_- b
fonte
1
"parece que não consegue fazê-lo funcionar como eu esperava." O que isso significa especificamente ?
precisa saber é o seguinte
Tenho certeza de que estou usando incorretamente, mas ao usar o código acima, posso usar duas conchas e fazer com que ambas editem o arquivo do contador enquanto eu pensava que uma estava bloqueando-o. Portanto, se eu executar essa linha duas vezes em duas conchas separadas, (cada uma com seu próprio número para ecoar), ainda vejo o segundo número sendo escrito
d -_- b
1
Quando o primeiro conclui e libera seu bloqueio, o segundo é executado. Não é assim que deve funcionar? (No código acima, && sleep 5é executado depois que o rebanho libera a trava.) #
3110 John1024
Hummm interessante ... Então, nesse caso, teria sido rápido demais para o meu olho humano pegar. Ótimo! Meu próximo desafio é como colocar vários comandos flock, mas vou colocar isso como uma pergunta separada. Obrigado John!
precisa
3
@d -_- b Adoro o seu nome de usuário. Esse é o nome de usuário mais inteligente que eu já vi.
Devyn Collier Johnson

Respostas:

10

O processamento do comando abaixo por Bash pode ser surpreendente:

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

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

Além de &versus&&

Se houver dois comandos, Ae B:

  1. A & Binicia Aem segundo plano e, em seguida, inicia Bsem esperar para Aterminar.

  2. A && Binicia A, aguarda a conclusão e, se concluir com êxito (código de saída 0), inicia B. Se Afalhar (código de saída diferente de zero), Bnunca será executado.

Em suma, &e &&são dois operadores de lista completamente diferentes.

John1024
fonte
3
me surpreenderia se estivesse dentro A && B, Aesperaria Bterminar.
Andras Gyomrey
1
em A&&B, A é executado primeiro. B é executado apenas se A for executado e encerrado com sucesso. Use um; B para sempre executar B, independentemente do status de execução de A.
kapad
15

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 (outro) verificar se ele foi bloqueado, ele saberá.

O objetivo flocké fazer coisas como o que você deseja, mas você deve usá-lo flockpara cada tentativa de acesso . Lembre-se de que estão bloqueando chamadas; de man flock:

se a trava não puder ser adquirida imediatamente, o rebanho aguardará até que a trava esteja disponível


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

Cachinhos Dourados
fonte
Obrigado! Isso ajuda a entender o aspecto 'consultivo' e como preciso usar flockcada vez. muito útil!
precisa
2

Você pode usar "sh -c command ..." para executar o comando shell inteiro, incluindo o redirecionamento de arquivo, com o bloqueio pressionado. Além disso, como você está usando o arquivo como um contador, mantenha a trava continuamente enquanto faz a leitura e a gravação novamente. 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 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 disputa possa ocorrer, portanto, não será necessário se preocupar com o bloqueio tão cedo:

echo 0 > /dev/shm/counter.txt

Eu não acho que você precisaria ignorar o valor do contador enquanto a disputa poderia ocorrer, mas, se você já fez, deve fazê-lo da seguinte maneira:

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

Eu acho que você entende como fazer a leitura, mas eu a incluo para completar:

flock --shared /dev/shm/counter.txt cat /dev/shm/counter.txt
Adam Richter
fonte
Esta parece ser a única resposta que percebe corretamente que, na pergunta, o arquivo é aberto pelo shell antes que o rebanho seja executado ...
eichin 18/03