Obtenga un bloqueo exclusivo de lectura / escritura en un archivo para actualizaciones atómicas

10

Quiero tener un archivo que se use como contador. El usuario A escribirá e incrementará este número, mientras que el usuario B solicita leer el archivo. ¿Es posible que el usuario A pueda bloquear este archivo para que nadie pueda leerlo o escribirlo hasta que finalice la escritura del usuario A?

Lo he investigado flockpero parece que no puedo hacerlo funcionar como lo espero.

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

¡Si hay una manera más apropiada de obtener este archivo incremental de tipo atómico, sería genial escucharlo también!

Mi meta es:

LOCK counter.txt; write to counter.txt;

mientras que al mismo tiempo

Read counter.txt; realize it's locked so wait until that lock is finished.
d -_- b
fuente
1
"Parece que no puedo hacer que funcione como lo espero". ¿Qué significa eso específicamente ?
John1024
Estoy seguro de que lo estoy usando incorrectamente, pero mientras uso el código anterior, puedo usar dos shells y hacer que ambos editen el archivo del contador mientras creía que uno lo estaba bloqueando. Entonces, si ejecuto esa línea dos veces en dos shells separados (cada uno con su propio número para hacer eco), todavía veo el segundo número escrito
d -_- b
1
Cuando el primero completa y libera su bloqueo, el segundo se ejecuta. ¿No es así como debería funcionar? (En el código anterior, && sleep 5se ejecuta después de que el lote libera el bloqueo.)
John1024
Hmm intersting ... Entonces, en ese caso, habría sido demasiado rápido para que mi ojo humano lo captara. ¡Excelente! Mi próximo desafío es cómo poner múltiples comandos flock, pero lo pondré como una pregunta separada. Gracias John!
d -_- b
3
@d -_- b Me encanta tu nombre de usuario. Ese es el nombre de usuario más inteligente que he visto.
Devyn Collier Johnson

Respuestas:

10

El procesamiento de Bash del comando a continuación puede ser sorprendente:

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

Bash primero se ejecuta flock -x -w 5 /dev/shm/counter.txt echo "4" > /dev/shm/counter.txty, si eso se completa con éxito (liberando el bloqueo), entonces se ejecuta sleep 5. Por lo tanto, el bloqueo no se mantiene durante los 5 segundos que uno puede esperar.

Aparte de &versus&&

Si uno tiene dos comandos, Ay B, entonces:

  1. A & Bcomienza Aen segundo plano y luego comienza Bsin esperar a Aque termine.

  2. A && Bcomienza A, espera a que se complete y luego, si se completa con éxito (código de salida 0), comienza B. Si Afalla (código de salida distinto de cero), Bnunca se ejecuta.

En suma, &y &&son dos operadores de listas completamente diferentes.

John1024
fuente
3
me sorprendería si en A && B, Aesperaría a Bque termine.
Andras Gyomrey
1
en A y B, A se ejecuta primero. B se ejecuta solo si A se ejecuta y sale con éxito. Utilizar un; B para ejecutar siempre B independientemente del estado de ejecución de A.
kapad
15

Los bloqueos de archivos no son obligatorios 1 , es decir, no puede bloquear un archivo para que otro proceso no pueda acceder a él. Bloquear un archivo significa que si un proceso (otro) verifica si se ha bloqueado, lo sabrá.

El propósito de flockes hacer cosas como lo que quieres, pero luego debes usarlas flockpara cada intento de acceso . Tenga en cuenta que esas son llamadas de bloqueo; de man flock:

Si la cerradura no se puede adquirir de inmediato, la bandada espera hasta que esté disponible


1. Lo que hace que la función parezca inútil si la está utilizando, por ejemplo, para seguridad, pero ese no es el propósito de los bloqueos de archivos: son para la sincronización, que es lo que está haciendo. El usuario Leo señaló que puede haber una implementación no estandarizada de bloqueo obligatorio de archivos en el kernel de Linux ( vea esta discusión ), en base a paralelos históricos de otros sistemas operativos * nix. Sin embargo, esto parece ser solo una interfaz de nivel C.

encerrada dorada
fuente
¡Gracias! Esto ayuda a dar sentido al aspecto 'consultivo' y a cómo debo usarlo flockcada vez. ¡muy útil!
d -_- b
2

Puede usar "sh -c command ..." para ejecutar todo el comando de shell, incluida la redirección de archivos, con el bloqueo retenido. Además, debido a que está utilizando el archivo como contador, debe mantener el bloqueo continuamente mientras lee y reescribe. Por lo tanto, querrá hacer algo como esto para incrementar el contador y devolver su nuevo 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))'

Cambiar los signos más a signos menos debería disminuir el 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 inicialice el contador antes de que ocurra cualquier disputa, por lo que no debería tener que preocuparse por bloquear tan temprano:

echo 0 > /dev/shm/counter.txt

No creo que alguna vez necesites cambiar el valor del contador mientras podría ocurrir una disputa, pero, si alguna vez lo hiciste, deberías hacerlo así:

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

Creo que entiendes cómo hacer la lectura, pero lo incluyo para completar:

flock --shared /dev/shm/counter.txt cat /dev/shm/counter.txt
Adam Richter
fuente
Esta parece ser la única respuesta que advierte correctamente que en la pregunta, el archivo se abre antes de que el
lote se