2010-03-19 19 views
15

Estoy tratando de aprender sobre las variables de condición. Me gustaría saber cuáles son las situaciones comunes en las que se usan variables de condición.¿Cuáles son los usos comunes de las variables de condición en C++?

Un ejemplo está en una cola de bloqueo, en el que dos hilos de acceder a la cola - el hilo productor empuja un elemento en la cola, mientras que el hilo consumidor aparece un elemento de la cola. Si la cola está vacía, el hilo del consumidor espera hasta que el hilo del productor envíe una señal.

¿Cuáles son otras situaciones de diseño en las que necesita usar una variable de condición?

Preferiría ejemplos basados ​​en la experiencia, como aquellos en aplicaciones reales.

+1

¿Debería ser una wiki comunitaria? – jasonline

+0

Ya que no está buscando una respuesta específica y simplemente más "respuestas" generales, probablemente. Pero estoy más cerca de este, es posible que desee esperar el no o el bien de los demás. – GManNickG

+2

+1 Toma esos puntos de reputación bien ganados mientras puedas para esta buena pregunta :-) –

Respuesta

2

Un uso de variables de condición que es un poco más complicado que una simple cola de mensajes, es el de "compartir una cerradura", donde los diferentes hilos están esperando sutilmente diferentes condiciones de la misma naturaleza básica. Por ejemplo, tienes un caché web (muy shonky, simplificado). Cada entrada en la memoria caché tiene tres estados posibles: no presente, IN_PROGRESS, COMPLETE.

getURL: 
    lock the cache 
    three cases for the key: 
     not present: 
      add it (IN_PROGRESS) 
      release the lock 
      fetch the URL 
      take the lock 
      update to COMPLETE and store the data 
      broadcast the condition variable 
      goto COMPLETE 
     COMPLETE: 
      release the lock and return the data 
     IN_PROGRESS: 
      while (still IN_PROGRESS): 
       wait on the condition variable 
      goto COMPLETE 

que tengo en la práctica utiliza el patrón de implementar una variante de la función POSIX pthread_once sin ninguna ayuda del planificador. La razón por la que no pude usar un semáforo o bloqueo por once_control, y simplemente hacer la inicialización bajo el bloqueo, es que no se permitió que la función fallara, y el once_control solo tenía una inicialización trivial. Para el caso, pthread_once no tiene códigos de error definidos, por lo que su implementación posiblemente falle no deja buenas opciones a su interlocutor ...

Por supuesto, con este patrón, debe tener cuidado con la escala. Cada vez que se completa una inicialización, cada subproceso de espera se activa para tomar el bloqueo. Entonces, cuando diseña el sistema, piensa detenidamente sobre la fragmentación, y luego decide que no se puede molestar en hacer nada para implementarlo realmente hasta que vea problemas de rendimiento probados.

1

Un ejemplo, además del modelo de consumidor-productor, que ya se ha mencionado es el uso en barrier synchronization. Cuando los hilos entran en la barrera, si todavía hay otros hilos que necesitan entrar en la barrera, entonces esperan una variable de condición. El último hilo para ingresar a la barrera señala la condición.

+0

@Michael: No estoy realmente familiarizado con las barreras ... pero en su ejemplo, ¿está diciendo que usó barreras con una variable de condición separada? Pensé que puedes implementar la situación anterior usando solo barreras y no necesitas una variable de condición separada. – jasonline

+0

@jasonline, por lo tanto, puede usar las barreras provistas por pthreads, pero también puede implementar su propia barrera usando un mutex y una variable de condición (que es como pthreads muy probablemente proporciona la suya). Cuando ingresa a la barrera, bloquea el mutex, incrementa el conteo y almacena el sentido de barrera. Si el conteo ha alcanzado el máximo, restablece el recuento a cero, invierte el sentido de barrera, señala la condición y sale de la barrera. De lo contrario, esperas con la condición, hasta que el sentido de barrera sea el opuesto al almacenado. –

+0

Ah, sí. Entiendo tu punto. Gracias. – jasonline

0

I utilizado para enviar mensajes sincronizados, que se añadió a-objeto de sincronización.
El objeto de sincronización consistió en una variable de condición con un booleano "listo".
En la función syncMsg :: send(), había una sincronización-> wait() y en la función syncMsg :: handle(), había una sincronización-> go().

Debe usarse con prudencia debido a posibles bloqueos.

0

Utilizo variables de condición en lugar de los objetos de eventos Win32 propensos a errores. Con condvars, no tienes que preocuparte tanto por la señalización espuria. También es más fácil esperar a que ocurran múltiples eventos.

Condvars También puede reemplazar los semáforos, ya que son más de uso general.

0

Sé que esto no es muy útil, pero yo uso variable de estado cada vez que quiero un hilo que esperar a que suceda algo o sólo esperar hasta que suceda algo.

Un patrón muy común para el lugar donde uso una variable de condición es un hilo de fondo que se activa cada pocos minutos para procesar y luego vuelve a dormirse. Al apagar el hilo principal, envía una señal al hilo de fondo para que termine y luego lo une terminando. El hilo de fondo espera en la condición con un tiempo de espera, para realizar su suspensión.

El subproceso de fondo sigue esta lógica básica

void threadFunction() { 
    initialisation(); 

    while(! shutdown()) { 
     backgroundTask(); 

     shutdown_condition_wait(timeout_value); 
    } 

    cleanup(); 
} 

Esto permite el apagado subproceso de fondo con prontitud y con gracia.

Si tengo varios de estos hilos, la función principal indica a cada uno que se apague y luego une cada uno después del siguiente. Esto permite que cada componente de hilo se cierre en paralelo.

Cuestiones relacionadas