UC3M

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

Arquitectura de Sistemas

Septiembre 2017 - Enero 2018

11.5.3. Lector-escritor multihilo

Plan de trabajo

La siguiente pieza de código está caracterizada por implementar un problema de tipo lector-escritor: el (hilo) lector lee datos del teclado y los guarda en una posición. Esta posición se lee más tarde cuando el (hilo) escritor escribe a una posición de memoria. El problema necesita que ambos hilos se bloqueen; el escritor debe esperar a que la posición de memoria quede libre, para no pisarla; y el segundo hilo necesita que haya algo que imprimir. Esta es la solución del problema:

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
/* compile with gcc -pthread *.c -o ./prod_consumer
 */
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0

char shared_array[204];
pthread_mutex_t lock= PTHREAD_MUTEX_INITIALIZER;
int string_read=FALSE;
pthread_cond_t cond= PTHREAD_COND_INITIALIZER;;
pthread_cond_t cond2= PTHREAD_COND_INITIALIZER;;

//Reader thread
void * read1()
{
        while(TRUE)
	{
		pthread_mutex_lock(&lock);
                while(string_read)
		{
		  pthread_cond_wait(&cond2,&lock);
		}
                printf("\n[TH1] Enter a string (100 characters): ");
                scanf("%100s",shared_array); //unsafe with more than 204 characters
                string_read=TRUE;
		pthread_cond_signal(&cond);
                pthread_mutex_unlock(&lock);
        }
}

//Writer thread
void * write1()
{
        while(TRUE)
	{
                pthread_mutex_lock(&lock);
                while(!string_read)
		{
                  pthread_cond_wait(&cond,&lock);
		}
                printf("\n[TH2]The string entered is: \"%s\"\n",shared_array);
                string_read=FALSE;
		pthread_cond_signal(&cond2);
                pthread_mutex_unlock(&lock);
        }
}
int main()
{
        int status;
        pthread_t tr;
	pthread_t tw;
        pthread_create(&tr,NULL,read1,NULL);
        pthread_create(&tw,NULL,write1,NULL);
        pthread_join(tr,NULL);
        pthread_join(tw,NULL);
        return 0;
} 

Algunos aspectos del problema:

  • La solución utiliza un cerrojo global lock para proteger todo acceso a la información compartida (tabla).

  • Utiliza dos variables de condición (cond, cond2) para que cada hilo pueda dormirse de forma segura con una operación wait.

  • Un hilo notifica al otro cuando ha terminado sobre su condición de variable correspondiente.

Sobre el ejemplo, le piden que realice las siguientes acciones:

  1. Baje el código lo compile y lo ejecute.

  2. Modifique el código para que la lectura scanf sin el cerrojo lock tomado. Pista: Divida la sección protegida en dos bloques copie las variables tras leer las variables.

  3. Modifique el código para sustituir la espera bloqueante por otra activa (con sleep de un segundo). ¿Cuál de las dos soluciones es más elegante: la de la espera de un segundo, o la que usa variables de condición?