Python | Bloqueo sin interbloqueos

Este artículo se centra en cómo obtener más de un bloqueo a la vez si se proporciona un programa multiproceso junto con evitar los puntos muertos. 

Programas de subprocesos múltiples: debido a los subprocesos que siguen intentando obtener múltiples bloqueos a la vez, estos son muy propensos a los puntos muertos. Entendiéndolo con un ejemplo: un hilo ya ha adquirido un bloqueo y luego el bloque intenta un segundo bloqueo; en ese caso, el programa puede congelarse ya que el hilo puede bloquear potencialmente el progreso de otros hilos. 
 

Solución: 

  • Cumplimiento de la regla de pedido
  • Asignando cada bloqueo de manera única al programa.
  • Solo permite adquirir múltiples bloqueos en orden ascendente.

Código #1: Implementación de la solución usando un administrador de contexto.
 

Python3

# importing libraries
import threading
from contextlib import contextmanager
 
# threading to stored information
_local = threading.local()
 
 
@contextmanager
def acquire(*lock_state_state):
 
    # Object identifier to sort the lock
    lock_state_state = sorted(lock_state_state, key=lambda a: id(a))
 
    # checking the validity of previous locks
    acquired = getattr(_local, 'acquired', [])
    if acquired and max(id(lock_state) for
                        lock_state in acquired) >= id(lock_state_state[0]):
        raise RuntimeError('lock_state Order Violation')
 
    # Collecting all the lock state.
    acquired.extend(lock_state_state)
    _local.acquired = acquired
 
    try:
    for lock_state in lock_state_state:
        lock.acquire()
    yield
    finally:
 
        # locks are released in reverse order.
        for lock_state in reversed(lock_state_state):
            lock_state.release()
        del acquired[-len(lock_state_state):]

Los bloqueos se adquieren de la manera normal usando el administrador de contexto y para realizar esta tarea se usa la función de adquisición() ya que había más de un bloqueo como se muestra en el código a continuación: 
 

Código #2: 

Python3

# threads
import threading
 
# creating locks
lock_state_1 = threading.Lock()
lock_state_2 = threading.Lock()
 
# using acquire as there are more than one lock
 
 
def thread_1():
    while True:
        with acquire(lock_state_1, lock_state_2):
            print('Thread-1')
 
 
def thread_2():
    while True:
        with acquire(lock_state_2, lock_state_1):
            print('Thread-2')
 
 
t1 = threading.Thread(target=thread_1)
 
# daemon thread runs without blocking
# the main program from exiting
t1.daemon = True
t1.start()
 
t2 = threading.Thread(target=thread_2)
t2.daemon = True
t2.start()
  • Incluso después de la adquisición de la especificación de bloqueos en un orden diferente en cada función, el programa se ejecutará para siempre sin puntos muertos.
  • Ordenar los bloqueos juega un papel importante de acuerdo con el identificador del objeto, ya que los bloqueos después de ser ordenados se adquieren de manera consistente, independientemente de cómo el usuario los haya proporcionado para adquirir().
  • Si se anidan varios subprocesos como se muestra en el código a continuación, para resolver un problema sutil con la detección de un punto muerto potencial, se utiliza el almacenamiento local de subprocesos.

Código #3:  

Python3

# threads
import threading
 
# creating locks
lock_state_1 = threading.Lock()
lock_state_2 = threading.Lock()
 
 
def thread_1():
    while True:
        with acquire(lock_state_1):
            with acquire(lock_state_2):
                print('Thread-1')
 
 
def thread_2():
    while True:
        with acquire(lock_state_2):
            with acquire(lock_state_1):
                print('Thread-2')
 
 
t1 = threading.Thread(target=thread_1)
 
# daemon thread runs without blocking
# the main program from exiting
t1.daemon = True
t1.start()
 
t2 = threading.Thread(target=thread_2)
t2.daemon = True
t2.start()

Al ejecutar esta versión del programa, uno de los subprocesos se bloqueará con una excepción como: 
 

Exception in thread Thread-1:
Traceback (most recent call last):
    File "/usr/HP/lib/python3.3/threading.py", line 639, in _bootstrap_inner
        self.run()
    File "/usr/HP/lib/python3.3/threading.py", line 596, in run
        self._target(*self._args, **self._kwargs)
    File "deadlock.py", line 49, in thread_1
        with acquire(y_lock):
    File "/usr/HP/lib/python3.3/contextlib.py", line 48, in __enter__
        return next(self.gen)
    File "deadlock.py", line 17, in acquire
        raise RuntimeError("Lock Order Violation")
RuntimeError: Lock Order Violation

Cada subproceso recuerda que el bloqueo ya se adquirió, por eso ha estado mostrando este error. Las restricciones de orden que adquirieron los bloqueos también se aplican y el método de adquisición() comprueba una lista de bloqueos adquiridos previamente.
 

Publicación traducida automáticamente

Artículo escrito por manikachandna97 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *