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 sleeps.
[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