Al igual que con semáforos, un programador podría pensar en ejecutar pthread_mutex_lock() en una hebra y luego pthread_mutex_unlock() en otra, pero eso no es posible. En POSIX cuando una hebra ejecuta pthreaad_mutex_lock() pasa a ser la dueña de ese candado (mutex) y es esa misma hebra debe ejecutar Pthread_mutex_unlock().
Las variables de condición son otro mecanismo de sincronización entre hilos. Las variables de condición usadas en conjunto con mutex permiten a un hilo esperar por la ocurrencia de una condición arbitraria. La espera es libre de carreras críticas.
Variables visibles a ambos hilos:
pthread_mutex_t lock_de_mi_variable = PTHREAD_MUTEX_INITIALIZER;
int variable = 0;
En una hebra: /* Espera por un valor superior a LIMITE en variable */
:
int deboEsperar = 1;
while (deboEsperar) { /*Espera activa u ocupada, indeseable */
pthread_ mutex_lock(&lock_de_mi_variable);
if ( variable > LIMITE) /* Alcanzó valor límite?*/
deboEsperar=0;
pthread_mutex_unlock(&lock_de_mi_variable);
}
/* hago lo que esperaba cuando variable > LIMITE */
:
|
En Otra hebra: : pthread_ mutex_lock(&lock_de_mi_variable); variable++; pthread_mutex_unlock(&lock_de_mi_variable); : |
| #include <pthread.h> int pthread_cond_init(pthread_cond_t *restrict cond, pthread_condattr_t *restrict attr); int pthread_cond_destroy(pthread_cond_t *restrict cond); Ambas retornan 0 si es OK, y un número de error en caso de falla. |
| #include <pthread.h> int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); int pthread_cond_timewait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict timeout); Ambas retornan 0 si es OK, y un número de error en caso de falla. |
Cuando un hilo invoca a pthread_cond_wait, éste libera el candado del mutex usado como argumento. Más adelante cuando es despertado, éste candado es devuelto a la hebra.
Hay dos funciones para notificar a hebras que una condición ha cambiado. La función pthread_cond_signal despertará a una hebra que espera con la misma variable de condición. La función pthread_cond_broadcast despierta a todas la hebras esperando por la condición.
| #include <pthread.h> int pthread_cond_signal(pthread_cond_t *restrict cond); int pthread_cond_broadcast(pthread_cond_t *restrict cond); Ambas retornan 0 si es OK, y un número de error en caso de falla. |
Con estas funciones el problema se resuelve de la siguiente manera:
Visibles a ambas hebras:
pthread_mutex_t lock_de_mi_variable = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cambioDeVariable = PTHREAD_COND_INITIALIZER;
int variable = 0;
En una hebra: /* Espera por un valor superior a LIMITE en variable para poder proseguir */
:
int deboEsperar = 1;
pthread_ mutex_lock(&lock_de_mi_variable);
while (deboEsperar) { /*Espera por condición */
if ( variable > LIMITE) /* Alcanzó valor límite?*/
deboEsperar=0;
else
pthread_cond_wait(&cambioDeVariable, &lock_de_mi_variable); /*espera bloqueada*/
}
pthread_mutex_unlock(&lock_de_mi_variable);
/* hago lo que esperaba cuando variable > LIMITE */
|
En Otra hebra: : pthread_ mutex_lock(&lock_de_mi_variable); variable++; pthread_mutex_unlock(&lock_de_mi_variable); pthread_cond_signal(&cambioDeVariable); : |
Alternativamente esta hebra se pudo programar así (más simple):
:
pthread_ mutex_lock(&lock_de_mi_variable);
while ( variable <= LIMITE ) /* Debo seguir esperando mi condición !*/
pthread_cond_wait(&cambioDeVariable, &lock_de_mi_variable);/*espera bloqueada*/
pthread_mutex_unlock(&lock_de_mi_variable);
/* hago lo que esperaba para variable > LIMITE */
:
|