Saltar al contenido

Bloqueo, mutex, semáforo … ¿cuál es la diferencia?

Te doy la bienvenida a nuestra web, en este lugar vas a encontrar la solucíon que buscas.

Solución:

Un candado permite que solo un hilo ingrese a la parte que está bloqueada y el candado no se comparte con ningún otro proceso.

Un mutex es lo mismo que un bloqueo, pero puede ser de todo el sistema (compartido por varios procesos).

Un semáforo hace lo mismo que un mutex pero permite que entren x número de subprocesos, esto se puede usar, por ejemplo, para limitar el número de tareas intensivas de cpu, io o ram que se ejecutan al mismo tiempo.

Para una publicación más detallada sobre las diferencias entre mutex y semáforo, lea aquí.

También tiene bloqueos de lectura / escritura que permiten un número ilimitado de lectores o 1 escritor en un momento dado.

Hay muchos conceptos erróneos sobre estas palabras.

Esto es de una publicación anterior (https://stackoverflow.com/a/24582076/3163691) que encaja perfectamente aquí:

1) Sección crítica= Objeto de usuario utilizado para permitir la ejecución de solo un hilo activo de muchos otros dentro de un proceso. Los otros subprocesos no seleccionados (@ adquiriendo este objeto) se colocan en dormir.

[No interprocess capability, very primitive object].

2) Semáforo Mutex (también conocido como Mutex)= Objeto de kernel utilizado para permitir la ejecución de solo un hilo activo de muchos otros, entre diferentes procesos. Los otros subprocesos no seleccionados (@ adquiriendo este objeto) se colocan en dormir. Este objeto admite propiedad de subprocesos, notificación de terminación de subprocesos, recursividad (múltiples llamadas ‘adquirir’ del mismo subproceso) y ‘evitación de inversión de prioridad’.

[Interprocess capability, very safe to use, a kind of ‘high level’ synchronization object].

3) Contando semáforo (también conocido como semáforo)= Objeto del kernel utilizado para permitir la ejecución de un grupo de hilos activos de muchos otros. Los otros subprocesos no seleccionados (@ adquiriendo este objeto) se colocan en dormir.

[Interprocess capability however not very safe to use because it lacks following ‘mutex’ attributes: thread termination notification, recursion?, ‘priority inversion avoidance’?, etc].

4) Y ahora, hablando de ‘spinlocks’, primero algunas definiciones:

Región crítica = Una región de memoria compartida por 2 o más procesos.

Lock = Una variable cuyo valor permite o niega la entrada a una ‘región crítica’. (Podría implementarse como una simple ‘bandera booleana’).

Ocupado esperando = Prueba continua de una variable hasta que aparezca algún valor.

Finalmente:

Spin-lock (también conocido como Spinlock)= A cerrar con llave que usa ocupado esperando. (La adquisición de la cerrar con llave Es hecho por xchg o similar operaciones atómicas).

[No thread sleeping, mostly used at kernel level only. Ineffcient for User level code].

Como último comentario, no estoy seguro, pero puedo apostarle mucho dinero a que los primeros 3 objetos de sincronización anteriores (n. ° 1, n. ° 2 y n. ° 3) hacen uso de esta simple bestia (n. ° 4) como parte de su implementación.

¡Que tenga un buen día!.

Referencias:

-Conceptos en tiempo real para sistemas integrados por Qing Li con Caroline Yao (CMP Books).

-Modern Operating Systems (3º) por Andrew Tanenbaum (Pearson Education International).

-Programación de aplicaciones para Microsoft Windows (4º) por Jeffrey Richter (Serie de programación de Microsoft).

Además, puede echar un vistazo a: https://stackoverflow.com/a/24586803/3163691

La mayoría de los problemas se pueden resolver usando (i) solo bloqueos, (ii) solo semáforos, … o (iii) una combinación de ambos. Como habrás descubierto, son muy similares: ambos previenen las condiciones de carrera, ambos tienen acquire()/release() operaciones, ambos causan que cero o más subprocesos se bloqueen / sospechen … Realmente, la diferencia crucial radica únicamente en cómo ellos bloquean y desbloquean.

  • A cerrar con llave (o mutex) tiene dos estados (0 o 1). Puede ser desbloqueado o bloqueado. A menudo se usan para garantizar que solo un hilo ingrese a una sección crítica a la vez.
  • A semáforo tiene muchos estados (0, 1, 2, …). Puede ser bloqueado (estado 0) o desbloqueado (estados 1, 2, 3, …). Uno o más semáforos a menudo se usan juntos para garantizar que solo un hilo ingrese a una sección crítica precisamente cuando el número de unidades de algún recurso ha alcanzado / no ha alcanzado un valor particular (ya sea mediante la cuenta regresiva hasta ese valor o contando hasta ese valor ).

Para ambos bloqueos / semáforos, intentando llamar acquire() mientras que la primitiva está en el estado 0 hace que se suspenda el hilo de invocación. Para cerraduras: los intentos de adquirir la cerradura en el estado 1 son satisfactorios. Para semáforos: los intentos de adquirir el bloqueo en los estados 1, 2, 3, … tienen éxito.

Para cerraduras en estado 0, si mismo hilo que había llamado previamente acquire(), ahora llama a liberar, entonces el lanzamiento es exitoso. Si un diferente hilo intentó esto – depende de la implementación / biblioteca en cuanto a lo que sucede (generalmente se ignora el intento o se arroja un error). Para semáforos en estado 0, alguna El subproceso puede llamar a release y será exitoso (independientemente del subproceso que se haya utilizado anteriormente para poner el semáforo en el estado 0).

De la discusión anterior, podemos ver que las cerraduras tienen la noción de un dueño (el único hilo que puede llamar a release es el propietario), mientras que los semáforos no tienen propietario (cualquier hilo puede llamar a release en un semáforo).


Lo que causa mucha confusión es que, en la práctica, son muchas variaciones de esta definición de alto nivel.

Variaciones importantes a considerar:

  • ¿Qué debería acquire()/release() ¿ser llamado? – [Varies massively]
  • ¿Su cerradura / semáforo utiliza una “cola” o un “conjunto” para recordar los hilos en espera?
  • ¿Se puede compartir su cerradura / semáforo con subprocesos de otros procesos?
  • ¿Su cerradura es “reentrante”? – [Usually yes].
  • ¿Su cerradura es “bloqueante / no bloqueante”? – [Normally non-blocking are used as blocking locks (aka spin-locks) cause busy waiting].
  • ¿Cómo se asegura de que las operaciones sean “atómicas”?

Esto depende de su libro / conferenciante / idioma / biblioteca / entorno.
Aquí hay un recorrido rápido que indica cómo algunos idiomas responden a estos detalles.


C, C ++ (subprocesos)

  • A mutex se implementa a través de pthread_mutex_t. De forma predeterminada, no se pueden compartir con ningún otro proceso (PTHREAD_PROCESS_PRIVATE), sin embargo, los mutex tienen un attribute llamado pshared. Cuando se establece, el mutex se comparte entre procesos (PTHREAD_PROCESS_SHARED).
  • A cerrar con llave es lo mismo que un mutex.
  • A semáforo se implementa a través de sem_t. De manera similar a los mutex, los semáforos se pueden compartir entre subprocesos de muchos procesos o mantenerse privados de los subprocesos de un solo proceso. Esto depende de la pshared argumento proporcionado a sem_init.

python (threading.py)

  • A cerrar con llave (threading.RLock) es casi igual que C / C ++ pthread_mutex_ts. Ambos son ambos reentrante. Esto significa que solo pueden desbloquearse mediante el mismo hilo que lo bloqueó. Es el caso que sem_t semáforos, threading.Semaphore semáforos y theading.Lock las cerraduras son no reentrante – porque es el caso alguna El hilo puede realizar desbloquear el bloqueo / bajar el semáforo.
  • A mutex es lo mismo que un candado (el término no se usa a menudo en Python).
  • A semáforo (threading.Semaphore) es casi lo mismo que sem_t. Aunque con sem_t, se utiliza una cola de ID de subprocesos para recordar el orden en el que los subprocesos se bloquearon al intentar bloquearlos mientras está bloqueado. Cuando un hilo desbloquea un semáforo, el primero Se elige el subproceso en la cola (si hay uno) para ser el nuevo propietario. El identificador del hilo se quita de la cola y el semáforo se vuelve a bloquear. Sin embargo, con threading.Semaphore, se usa un conjunto en lugar de una cola, por lo que el orden en el que se bloquearon los subprocesos no se almacena – alguna El hilo en el conjunto puede ser elegido para ser el próximo propietario.

Java (java.util.concurrent)

  • A cerrar con llave (java.util.concurrent.ReentrantLock) es casi igual que C / C ++ pthread_mutex_ty Python threading.RLock en que también implementa un bloqueo reentrante. Compartir bloqueos entre procesos es más difícil en Java debido a que la JVM actúa como intermediario. Si un hilo intenta desbloquear un candado que no es de su propiedad, IllegalMonitorStateException es aventado.
  • A mutex es lo mismo que un candado (el término no se usa a menudo en Java).
  • A semáforo (java.util.concurrent.Semaphore) es casi lo mismo que sem_t y threading.Semaphore. El constructor de semáforos Java acepta un justicia parámetro booleano que controla si se debe usar un conjunto (false) o una cola (true) para almacenar los hilos en espera.

En teoría, los semáforos se discuten a menudo, pero en la práctica, los semáforos no se usan tanto. Un semáforo solo tiene el estado de uno integer, por lo que a menudo es bastante inflexible y se necesitan muchos a la vez, lo que dificulta la comprensión del código. Además, el hecho de que alguna El hilo puede lanzar un semáforo a veces no es deseado. En su lugar, se utilizan más primitivas / abstracciones de sincronización orientadas a objetos / de nivel superior, como “variables de condición” y “monitores”.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

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