post

Exclusión, sincronización y región

exclusión a man and a woman communicating through hand gestures
Photo by cottonbro studio on Pexels.com

La programación concurrente, esencial en entornos de desarrollo modernos, involucra la ejecución simultánea de múltiples hilos o procesos para mejorar la eficiencia y la capacidad de respuesta de un programa.

Conceptos clave como la exclusión mutua, las regiones críticas y la sincronización juegan un papel fundamental. La exclusión mutua asegura que solo un hilo acceda a un recurso compartido en un momento dado, evitando así condiciones de carrera y garantizando la coherencia de los datos. Las regiones críticas, por su parte, son secciones de código donde se accede y modifica información compartida, y se implementan para garantizar que estas operaciones críticas se realicen de manera atómica, sin interferencia de otros hilos. La sincronización, coordina la ejecución de hilos para evitar conflictos y lograr un comportamiento predecible, utilizando mecanismos como cerrojos, variables de condición y semáforos. Estos conceptos son esenciales para desarrollar aplicaciones robustas y eficientes en entornos concurrentes. A continuación se muestra unos ejemplos

Ejemplo de exclusión mutua

Supongamos que se tiene una variable global compartida llamada contador. Se quiere garantizar que varios hilos puedan incrementar este contador sin que se pierdan actualizaciones debido a condiciones de carrera.

import threading

contador = 0
mutex = threading.Lock()

def incrementar():
    global contador
    for _ in range(1000000):
        with mutex:
            contador += 1

# Crear hilos
hilo_1 = threading.Thread(target=incrementar)
hilo_2 = threading.Thread(target=incrementar)

# Iniciar hilos
hilo_1.start()
hilo_2.start()

# Esperar a que ambos hilos terminen
hilo_1.join()
hilo_2.join()

print("Valor final del contador:", contador)

En este ejemplo, la exclusión mutua se logra utilizando un cerrojo (mutex). La sección crítica es la operación de incremento dentro del bucle. Solo un hilo puede ejecutar esta sección a la vez, asegurando que las actualizaciones al contador sean coherentes.

Ejemplo de de Región Crítica

Supongamos que se tiene una lista compartida y varios hilos que quieren agregar elementos a esta lista. Se necesita asegurar que la operación de agregar elementos se realice de manera segura.

import threading

lista_compartida = []
mutex = threading.Lock()

def agregar_elemento(elemento):
    with mutex:
        lista_compartida.append(elemento)

# Crear hilos
hilo_1 = threading.Thread(target=agregar_elemento, args=("A",))
hilo_2 = threading.Thread(target=agregar_elemento, args=("B",))

# Iniciar hilos
hilo_1.start()
hilo_2.start()

# Esperar a que ambos hilos terminen
hilo_1.join()
hilo_2.join()

print("Lista final:", lista_compartida)

Aquí, la región crítica es la operación de agregar elementos a la lista. El cerrojo (mutex) garantiza que solo un hilo pueda realizar esta operación a la vez, evitando problemas de concurrencia.

Ejemplo de Sincronización

Suponga que se tiene dos hilos: uno para imprimir números pares y otro para imprimir números impares en orden. Se Necesita sincronizarlos para asegurar que impriman alternadamente en orden.

import threading

mutex = threading.Lock()
condicion = threading.Condition()

def imprimir_pares():
    with mutex:
        for i in range(0, 10, 2):
            print(i)
            condicion.notify()
            condicion.wait()

def imprimir_impares():
    with mutex:
        for i in range(1, 10, 2):
            print(i)
            condicion.notify()
            condicion.wait()

# Crear hilos
hilo_pares = threading.Thread(target=imprimir_pares)
hilo_impares = threading.Thread(target=imprimir_impares)

# Iniciar hilos
hilo_pares.start()
hilo_impares.start()

# Esperar a que ambos hilos terminen
hilo_pares.join()
hilo_impares.join()

Aquí, se utiliza un objeto de condición (condicion) para sincronizar los hilos. La función notify() señala al otro hilo que puede imprimir, mientras que wait() hace que un hilo espere hasta que sea notificado por el otro. Esto asegura que los números pares e impares se impriman alternadamente en orden.

Dejar una respuesta

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