Python: Cómo sincronizar procesos y bloquear acceso a recursos

Una situación relativamente habitual cuando trabajamos con procesos es que dos o más tienen que acceder simultáneamente a un recurso que sólo puede usar uno a la vez. Un ejemplo podría ser el de una cámara de seguridad. Imaginemos dos procesos: uno de ellos, cuando se detecta movimiento, toma un vídeo, el otro proceso saca una foto de manera automática cada cinco minutos. Si el primer proceso está grabando vídeo cuando el segundo quiere sacar la foto no podrá hacerlo y tendremos un problema.

¿Cómo evitamos que dos procesos independientes accedan al mismo recurso a la vez en Python?

Para solucionar este problema podemos usar bloqueos de ficheros. Os dejo un ejemplo para que lo veáis de manera sencilla. En este caso vamos a tener dos procesos (prueba_bloqueo_A.py y prueba_bloqueo_B.py) que intentan acceder simultáneamente a un recurso limitado.

La “magia” se consigue gracias a fcntl.

Código de prueba_bloqueo_A.py:

Código de prueba_bloqueo_B.py:

Para verlos en acción puedes teclear en un terminal lo siguiente:

Los dos procesos se ejecutarán de manera concurrente. La salida puede ser similar a ésta:

¿Por qué digo que la salida puede ser “similar a ésta” y no “igual a ésta”? Porque, dado que trabajamos en un sistema multiproceso no tenemos garantía de que el proceso A sea más rápido o se ejecute antes que el proceso B.

Con este resultado vemos que ambos procesos solicitan acceso al recurso compartido, pero sólo uno de ellos lo conseguirá (el que antes lo solicite). El otro se queda esperando a que el primero termine. Luego será el primero el que espere a que termine el segundo.

La clase bloqueo (lock)

En este post (en inglés) Chris, además de dar un completo repaso a los bloqueos de procesos en Python, nos muestra una sencilla clase para controlas los bloqueos. Es lo mismo que hemos hecho más arriba pero de un modo más elegante:

Contenido del fichero bloqueos.py:

Y os dejo los anteriores scripts modificados para usar esta clase:

Contenido del fichero bloqueo_A.py:

Contenido de bloqueo_B.py:

Para ver el resultado teclear en un terminal:

Por último queda avisar que debemos tener cuidado y evitar que un proceso se quede colgado bloqueando un recurso de manera indefinida. No debemos olvidar los habituales try-except.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.