UC3M

Grado en Ing. Telemática/Sist. Audiovisuales/Sist. de Comunicaciones

Arquitectura de Sistemas

Septiembre 2015 - Enero 2016

11.4.2. Ejemplo de uso

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:

  1. Se crea una variable de condición.

  2. Cada hilo se duerme con un pthread_cond_waita la espera de un resultado.

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