Semáforos en Python

fondo

Ésta es una de las más antiguas primitivas de sincronización de la historia de la ciencia informática. Fue inventada por el informático teórico holandés Edsger W. Dijkstra (él utilizaba P() y V() en lugar de acquire() y release()).

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.

Un semáforo gestiona un contador interno que se decrementa en cada llamada a acquire() y se incrementa en cada llamada a release(). El contador nunca puede bajar de cero. Si una llamada a acquire() se encuentra el contador a cero, bloquea la ejecución del hilo en curso y queda a la espera de que otro hilo llame arelease().

Semaphore ([value])

El argumento opcional proporciona el valor inicial del contador interno. El valor predeterminado es 1.

acquire ([blocking])

Adquirir un semáforo.

Si se invoca sin argumentos: si el contador interno es superior a cero a la entrada, lo decrementa en una unidad y retorna de inmediato. Si es cero a la entrada, bloquear la ejecución del hilo, esperando a que otro llame a release() para hacerlo mayor de cero. Se gestionan de manera adecuada los interbloqueos, por lo que si hay varias llamadas a acquire() bloqueadas a la espera, release() despertará exactamente a una de ellas. La implementación puede seleccionar una al azar, por lo que no se debe confiar en un orden de respuesta observado. No hay valor de retorno en este caso.

Si se invoca con el argumento blocking a verdadero, hacer lo mismo que si se llama sin argumentos y devolver verdadero.

Si se invoca con blocking a falso, no bloquear. Si una llamada sin argumentos bloquearía, devolver falso de inmediato. En caso contrario, hacer lo mismo que si se llama sin argumentos y devolver verdadero.

release ()

Liberar un semáforo, incrementando su contador interno en una unidad. Si era cero a la entrada y otro hilo está esperando a que sea mayor que cero, despertar a dicho hilo.

Para ver su funcionamiento basta observar el siguiente ejemplo sencillo. En anteriores entradas del blog podemos observar todo lo relativo al módulo Threading. Por otro lado, se debe crear el semáforo indicando el valor inicial del contador (número máximo de hilos que pueden estar activos simultáneamente):

import threading

from time import sleep

n_sem = 1

semaforo = threading.Semaphore(n_sem)

class Hilo(threading.Thread):

def __init__(self, id):

threading.Thread.__init__(self)

self.id = id

def run(self):

semaforo.acquire()

print “Hilo %s entra.”%(self.id)

sleep(3)

semaforo.release()

hilos = [Hilo(1), Hilo(2), Hilo(3)]

for h in hilos:

h.start()

Referencias:

http://pyspanishdoc.sourceforge.net/lib/semaphore-objects.html

https://pythonr2.wordpress.com/2008/09/01/sincronizacion-de-hilos-en-python/

http://mundogeek.net/archivos/2008/04/18/threads-en-python/

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s