The solution to this problem is the condition variable: pthread_cond
, that by waiting operation (wait
) and notification (signal
)
allows integrated with the operating system an inactive waiting, blocked into a function. Let's see how to solve the previous problem with the variable condition:
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; } |
This code includes the following remakable characteristics:
It creates a condition variable.
Each thread is sleeping within a pthread_cond_wait
waiting for a result.
Each thread wakes up from a pthread_cond_signal
from the main
thread.
With this, the new output of the program no longer needs to do a periodic swept.
The new code is blocked until the thread notifies the main
with a signal. It also avoids
the problem of having to block oneself with artificial sleep
s.
[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