pthread_mutex_t pthread_mutex_lock pthread_mutex_init pthread example ejemplos c linux multithreading pthreads mutex

pthread_mutex_lock - pthread_mutex_t



¿Por qué necesitamos una verificación de condición antes de pthread_cond_wait (2)

Estoy tratando de aprender lo básico de pthread_cond_wait. En todos los usos, veo bien

if(cond is false) pthread_cond_wait

o

while(cond is false) pthread_cond_wait

Mi pregunta es, queremos cond_wait solo porque la condición es falsa. Entonces, ¿por qué debo tomar el dolor de poner explícitamente un bucle if / while? Puedo entender que sin ningún tipo de verificación si / mientras se realiza antes de cond_wait , lo lograremos directamente y no volveremos en absoluto. ¿Es la verificación de condición únicamente para resolver este propósito o tiene algún otro significado? Si para resolver una condición innecesaria espere, entonces poner una verificación de condición y evitar la cond_wait es similar al sondeo? Estoy usando cond_wait como este.

void* proc_add(void *name){ struct vars *my_data = (struct vars*)name; printf("In thread Addition and my id = %d/n",pthread_self()); while(1){ pthread_mutex_lock(&mutexattr); while(!my_data->ipt){ // If no input get in pthread_cond_wait(&mutexaddr_add,&mutexattr); // Wait till signalled my_data->opt = my_data->a + my_data->b; my_data->ipt=1; pthread_cond_signal(&mutexaddr_opt); } pthread_mutex_unlock(&mutexattr); if(my_data->end) pthread_exit((void *)0); } }

La lógica es que estoy pidiendo al hilo de entrada que procese los datos siempre que haya una entrada disponible y que señale al hilo de salida que la imprima.


Debe probar la condición bajo el mutex antes de esperar porque las señales de la variable de condición no están en cola (las variables de condición no son semáforos). Es decir, si un hilo llama a pthread_cond_signal() cuando no hay bloqueos bloqueados en pthread_cond_wait() en esa variable de condición, entonces la señal no hace nada.

Esto significa que si tienes un hilo establece la condición:

pthread_mutex_lock(&m); cond = true; pthread_cond_signal(&c); pthread_mutex_unlock(&m);

y luego otro hilo incondicionalmente esperado:

pthread_mutex_lock(&m); pthread_cond_wait(&c, &m); /* cond now true */

Este segundo hilo se bloquearía para siempre. Esto se evita haciendo que el segundo hilo verifique la condición:

pthread_mutex_lock(&m); if (!cond) pthread_cond_wait(&c, &m); /* cond now true */

Como cond solo se modifica con la exclusión mutua mantenida, esto significa que el segundo hilo espera si y solo si cond es falso.

La razón por la que un bucle while () se usa en un código robusto en lugar de en if () es porque pthread_cond_wait() no garantiza que no se activará de forma falsa. Usar un while () también significa que la señalización de la variable de condición es siempre segura: las señales "adicionales" no afectan la corrección del programa, lo que significa que puede hacer cosas como mover la señal fuera de la sección de código bloqueada.


Necesita un bucle while porque el hilo que se llama pthread_cond_wait puede pthread_cond_wait incluso cuando no se alcanza la condición que está esperando. Este fenómeno se llama "despertar espurio".

Esto no es un error, es la forma en que se implementan las variables condicionales.

Esto también se puede encontrar en las páginas del manual:

Pueden producirse activaciones espurias de las funciones pthread_cond_timedwait () o pthread_cond_wait (). Dado que el retorno de pthread_cond_timedwait () o pthread_cond_wait () no implica nada sobre el valor de este predicado, el predicado debe reevaluarse en dicho retorno .

Actualización sobre el código actual:

void* proc_add(void *name) { struct vars *my_data = (struct vars*)name; printf("In thread Addition and my id = %d/n",pthread_self()); while(1) { pthread_mutex_lock(&mutexattr); while(!my_data->ipt){ // If no input get in pthread_cond_wait(&mutexaddr_add,&mutexattr); // Wait till signalled } my_data->opt = my_data->a + my_data->b; my_data->ipt=1; pthread_cond_signal(&mutexaddr_opt); pthread_mutex_unlock(&mutexattr); if(my_data->end) pthread_exit((void *)0); } } }