UC3M

Telematic/Audiovisual Syst./Communication Syst. Engineering

Systems Architecture

September 2015 - January 2016

11.4.2.  Use case

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:

  1. It creates a condition variable.

  2. Each thread is sleeping within a pthread_cond_wait waiting for a result.

  3. 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