Los locks, también llamados mutex
son objetos con dos estados posibles: adquirido o libre. Cuando un thread
adquiere la barrera, los demás threads que pidan adquirirlo se bloquearán hasta
que el thread que lo ha adquirido libere la barrera, momento en el cual podrá
entrar otro thread.
La barrera se representa mediante
la clase Lock. Llamando a Lock.acquire() el hilo bloqueará el Lock, de forma
que el siguiente hilo que llame a Lock.acquire() se quedará a la espera de que
el Lock se desbloquee. La llamada a Lock.release() desbloquea el Lock, haciendo
que el hilo que estaba en espera continúe. Un ejemplo se muestra a continuación:
from threading import Thread, Lock import time class MiHilo(Thread): def __init__ (self, inicio, fin, bloqueo): Thread.__init__(self) self.inicio = inicio self.fin = fin self.bloqueo = bloqueo def run (self): bloqueo.acquire() for i in range(self.inicio,self.fin): print ("contador = "+str(i)) time.sleep(0.2) bloqueo.release() if __name__ == '__main__': bloqueo = Lock() bloqueo.acquire() hilo = MiHilo(0,10, bloqueo) hilo.start() time.sleep(1) for i in range (10,20): print ("main = "+str(i)) time.sleep(0.1) bloqueo.release()
Esta clase Lock es muy simple.
Cualquier hilo, puede liberar a otro sin importar si lo haya bloquedado o no, además
si un hilo llama él mismo dos veces a acquire(), se queda bloqueado en la
segunda llamada. Una mejor opción es RLock. En esta barrera solo el que haya
llamado al método acquire() puede liberarlo con el método release() y un mismo
hilo puede llamar varias veces a acquire() sin quedarse bloqueado, pero tiene
que hacer el mismo número de llamadas a release() para desbloquearlo. El
ejemplo siguiente muestra su funcionamiento:
from threading import Thread, RLock import time class MiHilo(Thread): def __init__ (self, inicio, fin, bloqueo): Thread.__init__(self) self.inicio = inicio self.fin = fin self.bloqueo = bloqueo def run (self): bloqueo.acquire() for i in range(self.inicio,self.fin): print ("contador = "+str(i)) time.sleep(0.2) bloqueo.release() if __name__ == '__main__': bloqueo = RLock() bloqueo.acquire() hilo = MiHilo(0,10, bloqueo) hilo.start() time.sleep(1) for i in range (10,20): print ("main = "+str(i)) bloqueo.acquire() time.sleep(0.1) bloqueo.release() print ("El hilo todavia no ha comenzado") for i in range(10,20): bloqueo.release()
Semáforos
Un semáforo permite acceder a un determinado recurso a un
número máximo de hilos simultáneamente. Si hay más hilos que el máximo
permitido, los pone en espera y los va dejando pasar según van terminando los
que están activos. Un semáforo actúa como un contador con un valor inicial.
Cada vez que un hilo llama a Semaphore.acquire(),
el contador se decrementa en 1 y se deja pasar al hilo. En el momento que el
contador se hace cero, NO se deja pasar al siguiente hilo que llame a acquire(), sino que lo deja
bloqueado. Cada vez que se llama a Semaphore.release(),
el contador se incrementa en 1. Si se hace igual a cero, libera al siguiente
hilo en la cola de espera. El ejemplo de su funcionamiento se muestra a continuación:
from threading import Thread, Semaphore import time, random class MiHilo(Thread): def __init__(self, numero_hilo, semaforo): Thread.__init__(self) self.semaforo=semaforo self.numero_hilo = numero_hilo def run(self): semaforo.acquire() print ("Entra hilo "+str(self.numero_hilo)) time.sleep(random.randrange(1,10,1)) print ("Fin hilo " + str(self.numero_hilo)) semaforo.release() if __name__ == '__main__': random.seed() semaforo = Semaphore(5) for i in range(0,10): hilo=MiHilo(i,semaforo) hilo.start() print ("Arrancado hilo "+str(i))
La información y los ejemplos se
obtuvieron de las siguientes fuentes:
Los ejemplos se pueden descargar
del siguiente link.
No hay comentarios.:
Publicar un comentario