sistemas operativos multithreading operating-system synchronization semaphore mutual-exclusion

multithreading - operativos - Variable Condicional vs Semáforo



semaphore java (5)

Archivo variables de condición bajo sincronización de monitor. En general, he visto semáforos y monitores como dos estilos de sincronización diferentes. Existen diferencias entre los dos en términos de cuánto se conservan los datos de estado y cómo se desea modelar el código, pero realmente no hay ningún problema que pueda ser resuelto por uno, sino por el otro.

Tiendo a codificar hacia la forma del monitor; en la mayoría de los lenguajes en los que trabajo, se reduce a mutexes, variables de condición y algunas variables de estado de respaldo. Pero los semáforos también harían el trabajo.

¿Cuándo se debe usar un semáforo y cuándo se debe usar una variable condicional (CondVar)?


Los bloqueos se usan para la exclusión mutua. Cuando desee asegurarse de que un fragmento de código sea atómico, colóquelo alrededor. En teoría, podría usar un semáforo binario para hacer esto, pero ese es un caso especial.

Los semáforos y las variables de condición se basan en la exclusión mutua proporcionada por los bloqueos y se utilizan para proporcionar acceso sincronizado a los recursos compartidos. Se pueden usar para propósitos similares.

Una variable de condición se usa generalmente para evitar la espera ocupada (bucle repetidamente mientras se comprueba una condición) mientras se espera que un recurso esté disponible. Por ejemplo, si tiene un hilo (o varios hilos) que no puede continuar hasta que una cola esté vacía, el enfoque de espera ocupado sería simplemente hacer algo como:

//pseudocode while(!queue.empty()) { sleep(1); }

El problema con esto es que estás perdiendo el tiempo del procesador haciendo que este hilo revise la condición repetidamente. ¿Por qué no tener una variable de sincronización que se pueda señalar para indicar al hilo que el recurso está disponible?

//pseudocode syncVar.lock.acquire(); while(!queue.empty()) { syncVar.wait(); } //do stuff with queue syncVar.lock.release();

Presumiblemente, tendrás un hilo en otro lugar que está sacando cosas de la cola. Cuando la cola está vacía, puede llamar a syncVar.signal() para syncVar.signal() un hilo aleatorio que está dormido en syncVar.wait() (o generalmente también hay un signalAll() o broadcast() para signalAll() todos los hilos que están esperando).

Generalmente uso variables de sincronización como esta cuando tengo uno o más hilos esperando en una sola condición particular (por ejemplo, para que la cola esté vacía).

Los semáforos se pueden usar de manera similar, pero creo que se usan mejor cuando se tiene un recurso compartido que puede estar disponible y no disponible en función de un número entero de cosas disponibles. Los semáforos son buenos para situaciones de productores / consumidores en los que los productores asignan recursos y los consumidores los consumen.

Piense si tenía una máquina expendedora de refrescos. Solo hay una máquina de refrescos y es un recurso compartido. Usted tiene un hilo que es un vendedor (productor) que es responsable de mantener la máquina abastecida y N hilos que son compradores (consumidores) que quieren sacar refrescos de la máquina. El número de gaseosas en la máquina es el valor entero que controlará nuestro semáforo.

Cada hilo de comprador (consumidor) que llega a la máquina de soda llama al método de semáforo down() para tomar un refresco. Esto tomará un refresco de la máquina y disminuirá el recuento de refrescos disponibles en 1. Si hay gaseosas disponibles, el código seguirá corriendo más allá de la declaración down() sin ningún problema. Si no hay gaseosas disponibles, el hilo dormirá aquí esperando que se le notifique cuando vuelva a haber soda disponible (cuando haya más refrescos en la máquina).

El hilo del proveedor (productor) esencialmente esperaría que la máquina de soda esté vacía. El vendedor recibe una notificación cuando se retira el último refresco de la máquina (y uno o más consumidores están esperando a que salga la gaseosa). El proveedor reabastecería la máquina de refrescos con el método de semáforo up() , el número disponible de refrescos se incrementaría cada vez y, por lo tanto, los hilos del consumidor en espera serían notificados de que había más refresco disponible.

Los métodos wait() y signal() de una variable de sincronización tienden a ocultarse dentro de las operaciones down() y up() del semáforo.

Ciertamente, hay una superposición entre las dos opciones. Hay muchos escenarios en los que un semáforo o una variable de condición (o un conjunto de variables de condición) podrían servir para sus propósitos. Tanto los semáforos como las variables de condición están asociados con un objeto de bloqueo que utilizan para mantener la exclusión mutua, pero luego proporcionan una funcionalidad adicional en la parte superior del bloqueo para sincronizar la ejecución de subprocesos. En su mayor parte depende de usted averiguar cuál tiene más sentido para su situación.

Esa no es necesariamente la descripción más técnica, pero así es como tiene sentido en mi cabeza.


Los semáforos se pueden utilizar para implementar el acceso exclusivo a las variables, sin embargo, están destinados a ser utilizados para la sincronización. Los mutexes, por otro lado, tienen una semántica que está estrictamente relacionada con la exclusión mutua: solo el proceso que bloqueó el recurso puede desbloquearlo.

Desafortunadamente no se puede implementar la sincronización con mutexes, es por eso que tenemos variables de condición. También tenga en cuenta que con las variables de condición puede desbloquear todos los subprocesos en espera en el mismo instante utilizando el desbloqueo de difusión. Esto no se puede hacer con semáforos.


Revelemos lo que hay debajo del capó.

La variable condicional es esencialmente una cola de espera , que admite operaciones de bloqueo-espera y activación, es decir, puede poner un hilo en la cola de espera y establecer su estado en BLOQUE, y obtener un hilo de él y establecer su estado en LISTA.

Tenga en cuenta que para usar una variable condicional, se necesitan otros dos elementos:

  • una condición (típicamente implementada al marcar una bandera o un contador)
  • un mutex que protege la condición

El protocolo luego se convierte en

  1. adquirir mutex
  2. condición de verificación
  3. bloquear y liberar mutex si la condición es verdadera, de lo contrario, liberar mutex

Semáforo es esencialmente un contador + un mutex + una cola de espera. Y se puede usar tal cual sin dependencias externas. Puede usarlo como un mutex o como una variable condicional.

Por lo tanto, el semáforo se puede tratar como una estructura más sofisticada que la variable condicional, mientras que el segundo es más ligero y flexible.


las variables de semáforo y condición son muy similares y se usan principalmente para los mismos fines. Sin embargo, existen diferencias menores que podrían hacer que uno sea preferible. Por ejemplo, para implementar la sincronización de barrera no sería posible usar un semáforo. Pero una variable de condición es ideal.

La sincronización de barrera es cuando desea que todos sus hilos esperen hasta que todos hayan llegado a una determinada parte en la función de hilo. esto se puede implementar teniendo una variable estática que es inicialmente el valor de los hilos totales decrementados por cada hilo cuando alcanza esa barrera. esto significaría que queremos que cada hilo duerma hasta que llegue el último. ¡Un semáforo haría exactamente lo contrario! con un semáforo, cada subproceso se mantendría en ejecución y el último subproceso (que establecerá el valor de semáforo en 0) se irá a dormir.

una variable de condición, por otro lado, es ideal. cuando cada hilo llega a la barrera comprobamos si nuestro contador estático es cero. si no, configuramos el hilo para que duerma con la función de espera de la variable de condición. cuando el último hilo llega a la barrera, el valor del contador se reducirá a cero y este último hilo llamará a la función de señal de variable de condición que despertará a todos los otros hilos.