9

Tengo una unidad de red (Z: \) compartida por varias computadoras con Windows. ¿Es posible implementar un bloqueo entre máquinas simplemente creando/eliminando archivos en esta unidad de red?Implementación de bloqueo distribuido usando archivos

Por ejemplo, dos computadoras, A y B, desean escribir en un recurso compartido con una ID de 123 al mismo tiempo.

Una de las computadoras, por ejemplo A, bloquea el recurso primero al crear un archivo vacío Z: \ locks \ 123. Cuando B ve que hay un archivo de bloqueo con el nombre "123", B sabe que el recurso 123 está siendo utilizado por otra persona, por lo que tiene que esperar a que Z: \ locks \ 123 sea eliminado por A antes de que pueda acceder al recurso.

Es como la sección crítica en multihilo, pero quiero hacerlo en varias máquinas.

Estoy tratando de implementar en Python. Esto es lo que ocurrió:

import os 
import time 


def lock_it(lock_id): 

    lock_path = "Z:\\locks\\" + lock_id 
    while os.path.exists(lock_path): 
     time.sleep(5) # wait for 5 seconds 

    # create the lock file 
    lock_file = open(lock_path, "w") 
    lock_file.close() 


def unlock_it(lock_id): 

    # delete the lock file 
    lock_path = "Z:\\locks\\" + lock_id 
    if os.path.exists(lock_path): 
     os.remove(lock_path) 

esto no funcionará porque podría haber más de un procesos de salir del estado de espera y crear el archivo de bloqueo al mismo tiempo.

De nuevo, la pregunta es: ¿Es posible implementar un mecanismo de bloqueo entre máquinas en un almacenamiento compartido?

Respuesta

5

... tipo de.

Primero, debe crear un directorio de bloqueo en lugar de un archivo de bloqueo. La creación de un directorio (ver os.mkdir) fallará si el directorio ya existe, para que pueda adquirir el bloqueo de esta manera:

while True: 
    try: 
     os.mkdir(r"z:\my_lock") 
     return 
    except OSError as e: 
     if e.errno != 21: # Double check that errno will be the same on Windows 
      raise 
     time.sleep(5) 

En segundo lugar (y aquí es donde la "especie de" entra en juego) que querrá alguna forma de darse cuenta cuando la persona que tiene el candado ha muerto. Una forma simple de hacer esto podría ser hacer que ocasionalmente actualicen un archivo dentro del directorio de bloqueo. Luego, si los clientes notan que el archivo no se ha actualizado por un tiempo, pueden eliminar el directorio e intentar adquirir el bloqueo ellos mismos.

+1

¿Qué le parece agregar tiempo de espera? es decir, después de un período de tiempo, digamos 60 segundos, el bloqueo se libera automáticamente. Suponiendo que el tiempo de bloqueo no exceda este tiempo de espera. Puedo obtener el tiempo de bloqueo con time.time() - os.path.getctime ("Z: \ my_lock") para verificar si un bloqueo está vencido. – eliang

2

Esto no funcionará tan bien como podría esperar. Tendrá otros problemas, como que la unidad de red se vaya, en cuyo caso todos sus procesos se estancarán o pensará que nadie tiene un bloqueo.

Le sugiero que busque algo como ZooKeeper. Podrá crear bloqueos síncronos y recuperarse en caso de fallas de la red. El marco detrás de los bloqueos distribuidos es mucho más complejo que crear un archivo en una unidad de red.

+0

Estaba pensando en Memcache o en el software de cola como Beanstalk. – aitchnyu