71

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

+0

Información relacionada también se puede encontrar en el enlace http://stackoverflow.com/questions/4039899/when-should-we-use-mutex-and-when-should-we-use-semaphore –

Respuesta

145

Las cerraduras se utilizan 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 recursos compartidos. Se pueden usar para propósitos similares.

Una variable de condición generalmente se usa para evitar la espera ocupada (bucle repetidamente mientras se comprueba una condición) mientras se espera que un recurso esté disponible. Por ejemplo, si usted tiene un hilo (o múltiples hilos) que no puede seguir adelante hasta una cola está vacía, el enfoque de espera ocupada 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á un hilo en otro lugar que está sacando cosas de la cola. Cuando la cola está vacía, puede llamar al syncVar.signal() para activar un hilo aleatorio que está dormido en syncVar.wait() (o también suele haber un método signalAll() o broadcast() para activar todos los hilos que están esperando).

Generalmente uso variables de sincronización como esta cuando tengo uno o más subprocesos esperando en una sola condición en 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.

Piensa si tienes 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 refrescos 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 gaseosas 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) estaría esencialmente esperando a que la máquina de refrescos 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 vendedor 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 recibirían notificaciones de que hay más refrescos disponibles.

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.

Sin duda, 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.

+6

Wow !! Excelente respuesta – user373215

+0

Eso fue realmente útil. Gracias Brent. – ashu

+7

Gran respuesta, me gustaría agregar de otras respuestas: Semaphore se utiliza para controlar el número de subprocesos que se ejecutan. Habrá un conjunto fijo de recursos. El conteo de recursos disminuirá cada vez que un hilo sea el mismo. Cuando el recuento de semáforos llega a 0, no se permiten otros subprocesos para adquirir el recurso. Los hilos se bloquean hasta que otros hilos posean lanzamientos de recursos. En resumen, la principal diferencia es ¿cuántos subprocesos se permiten adquirir el recurso a la vez? Mutex --es UNA. Semáforo: su DEFINED_COUNT, (tantos como el conteo de semáforos) – berkay

13

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.

Lamentablemente no 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.

1

I archivo de variables de condición en la sincronización del 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.

+2

Esta sería una mejor respuesta si explicara qué es "forma de monitor". –

21

Revelemos lo que hay debajo del capó.

la variable condicional es esencialmente una espera de cola de, que apoya el bloqueo-esperar y despertarè operaciones, es decir, se puede poner un hilo en la espera en cola y establecer su estado de bloquear, y obtener un hilo fuera de ella y establecer su estado en LISTO.

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

  • una condición (implementado típicamente mediante la comprobación de una bandera o un contador)
  • un mutex que protege la condición

El protocolo se convierte entonces,

  1. adquirir mutex
  2. condición de comprobación
  3. bloque y la liberación mutex si la condición es verdadera, mutex liberación más

semáforo es esencialmente un una cola de espera contador + un mutex +. 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 último es más ligero y flexible.

+0

¡Gran reseña sobre la naturaleza de estos primitivos! –

3

las variables de semáforo y condición son muy similares y se utilizan principalmente para los mismos fines. Sin embargo, hay 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 condición variable, 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.

Cuestiones relacionadas