La solución a dicha problemática es la variable de condición: pthread_cond
, que mediante la operación de espera (wait
)
y notificación (signal
) permite realizar de forma integrada con el sistema operativo una espera no activa, de tipo bloqueante. Veamos cómo
solucionar el problema anterior con la variable de condición:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | // compile with $ gcc -Wall -g *.c -pthread -o program // run with ./program // check with valgrind --tool=helgrind ./program #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> pthread_mutex_t mutex; pthread_cond_t cond; void* thread_run(void* data_exit) { int i_tmp=-1; sleep(2); printf("[TH_ID:%ld]: Hello from the thread \n", pthread_self()); printf("[TH_ID:%ld]: Reading %i \n", pthread_self(),(*(int*)data_exit)); i_tmp=(*(int*)data_exit); pthread_mutex_lock(&mutex); for(;i_tmp==0;) { i_tmp=(*(int*)data_exit); if(i_tmp!=0) { (*(int*)data_exit)--; pthread_mutex_unlock(&mutex); return data_exit; } else { printf("[TH_ID:%ld]:let's wait, data is %i \n", pthread_self(),i_tmp); pthread_cond_wait(&cond,&mutex); //sleep(2); } } printf("[TH_ID:%ld]: Writing %i \n", pthread_self(),(*(int*)data_exit)); printf("[TH_ID:%ld]: To exit...............\n",pthread_self()); return data_exit; } int main() { int i; pthread_t thread[2]; int i_salir=0; //Number of threads that may exit int thread_rc; if(pthread_mutex_init(&mutex,NULL)!=0) return -1; if(pthread_cond_init(&cond,NULL)!=0) return -1; for (i=0;i<2; i++) { printf("[MAIN:%ld]: Starting............ \n",pthread_self()); if ((thread_rc=pthread_create(&thread[i],NULL,thread_run,&i_salir))!=0) { printf("Error creating the thread. Code %i",thread_rc); return -1; } } sleep(1); printf("[MAIN:%ld]: Thread allocated \n",pthread_self()); sleep(3); //Say to the thread you should exit pthread_mutex_lock(&mutex); pthread_cond_signal(&cond); pthread_cond_signal(&cond); i_salir=2; pthread_mutex_unlock(&mutex); int *ptr_output_data; for ( i=0;i<2; i++) { pthread_join(thread[i],(void **)&ptr_output_data); } pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond); printf("[MAIN:%ld]: Thread pending to return %d \n",pthread_self(), *ptr_output_data); return 0; } |
Este código incorpora las siguientes características principales:
Se crea una variable de condición.
Cada hilo se duerme con un pthread_cond_wait
a la espera de un resultado.
Cada hilo se despierta con pthread_cond_signal
desde el hilo del main
.
Con esto, la nueva salida del programa ya no necesita hacer un barrido periódico.
El nuevo código se bloquea hasta que el main
notifica al hilo con una unidad de una
señalización.También evita el problema de tener que bloquearse con sleep
s artificiales.
[MAIN:2]: Starting............ [MAIN:2]: Starting............ [MAIN:2]: Thread allocated [TH_ID:0]: Hello from the thread [TH_ID:0]: Reading 0 [TH_ID:0]: Let's wait, 0 [TH_ID:6]: Hello from the thread [TH_ID:6]: Reading 0 [TH_ID:6]: Let's wait, 0 [MAIN:2]: Thread pending to return 0