Está en la página 1de 19

UNIVERSIDAD NACIONAL DE SAN AGUSTIN

FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS


ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 1

GUÍA DE LABORATORIO
INFORMACIÓN BÁSICA

ASIGNATURA: Sistemas Operativos


TÍTULO DE LA
Exclusión mutua para PTHREADS
PRÁCTICA:
NÚMERO DE NRO.
7 AÑO LECTIVO: 2023 B
PRÁCTICA: SEMESTRE:
INDIVIDUAL
TIPO DE X
PRÁCTICA: MÍNIMO DE MÁXIMO DE
GRUPAL 10 15
ESTUDIANTES ESTUDIANTES
FECHA INICIO: 23/10/2023 FECHA FIN: 27/10/2023 DURACIÓN: 2 horas
RECURSOS Y EQUIPOS A UTILIZAR:
Ubuntu Linux, gcc, Computador personal, lapiz, papel
DOCENTE(s):
Msc Roni Guillermo Apaza Aceituno

OBJETIVOS/TEMAS Y COMPETENCIAS
OBJETIVOS:
- Implementar cerraduras mutex en pthreads
- Aplicar soluciones al problema de exclusión mutua
TEMAS:
• Estructura de la función phtread_mutex_lock
• Estructura de la función phtread_mutex_unlock
• Exclusión mutua

COMPETENCIAS C.a Aplica de forma transformadora conocimientos de matemática, computación e


A ALCANZAR ingeniería como herramienta para evaluar, sintetizar y usar las estrategias implementadas
por los Sistemas Operativos como fundamento de sus ideas y perspectivas para la
resolución de problemas.
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 2

CONTENIDO DE LA GUÍA
I. MARCO CONCEPTUAL
Problemas de concurrencia con Pthreads
Cuando decidimos trabajar con programas concurrentes uno de los mayores problemas con los que nos
podremos encontrar, y que es inherente a la concurrencia, es el acceso a variables y/o estructuras
compartidas o globales. Esto se entenderá mejor con un ejemplo:

Hilo 1
void *funcion_hilo_1(void *arg)
{
int resultado;
...
if (i == valor_cualquiera) {
...
resultado = i * (int)*arg;
...
}
pthread_exit(&resultado);
}

Hilo 2
void *funcion_hilo_2(void *arg)
{
int otro_resultado;
...
if (funcion_sobre_arg(*arg) == 0) {
...
i = *arg;
...
}
pthread_exit(&otro_resultado);
}

Este código, que tiene la variable 'i' como global, aparentemente es inofensivo, pero nos puede traer muchos
problemas si se ejecuta en paralelo y se dan ciertas condiciones.
Supongamos que el hilo 1 se empieza a ejecutar antes que el hilo 2, y que casualmente se produce un cambio
de contexto (el sistema operativo suspende la tarea actual y pasa a ejecutar la siguiente) justo después de la
línea que dice if (i==valor_cualquiera). La entrada en ese if se producirá si se cumple la condición, que
suponemos que sí.
Pero justo en ese momento el sistema hace un cambio de contexto y pone a ejecutar al hilo2, que se ejecuta
el tiempo suficiente como para ejecutar la línea i = *arg. Al poco rato hilo 2 deja de ejecutarse y vuelve a
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 3

ejecutarse el hilo 1, pero, ¿qué valor tiene ahora i? ¿El que el hilo 1 está "suponiendo" que tiene (o sea, el
mismo que comprobó al entrar en el if) o el que le ha asignado el hilo 2? La respuesta es fácil... ;-) i ha
tomado el valor que le asignó hilo 2, con lo que el resultado que devolverá el hilo 1 después de sus cálculos
será totalmente inválido e inesperado.
Claro que todo esto puede que no pasará si el sistema tuviera muy pocos procesos en ese momento (con lo
cual cada proceso se ejecutaría por más rato) y si el código del hilo 1 fuera lo suficientemente corto como
para no sufrir ningún cambio de contexto en medio de su ejecución... Pero NUNCA deberemos hacer
suposiciones de éstas, porque no sabremos dónde se van a ejecutar nuestros programas y siempre más vale
prevenir.
El problema que tienen estos bugs es que son los más difíciles de detectar en el caso que no nos fijáramos en
que podría pasar una cosa de estas el día que escribimos el código. Puede que a veces vaya todo a la
perfección y que otras salga todo mal... A esto se le conoce por Race Conditions (Condiciones de Carrera)
porque según como vaya la cosa puede funcionar o no.

Mecanismos de Pthreads para prevenir esto

La biblioteca de hilos en Linux incorpora Locks o Mutexes, para proteger regiones críticas del código, y las
llamadas básicas son las siguientes: pthread_mutex_init, pthread_mutex_lock , pthread_mutex_unlock y
pthread_mutex_destroy .
Notamos que tenemos llamadas para destruir el objeto Mutex a fin de liberar los recursos que este pueda
consumir.
En este caso nuestro ejemplo sincroniza los accesos a un buffer compartido por parte de dos componentes,
donde una establece un valor i en todo el buffer y la otra un valor j distinto. La idea es que queremos que se
mantenga el invariante que todo hilo externo siempre vea el buffer con un contenido uniforme de valores, ya
sea i o j.
Claramente si no protegemos con regiones críticas, es posible que a la mitad de una actualizacion, que no es
atómica, se produzca un cambio de contexto, ya sea para inspeccionar los valores o para establecerlos en
otro valor.
Lo que sigue es el programa setBuffer que implementa esta idea y protege a las secciones críticas utilizando
Locks.

Las funciones que ofrece Pthreads para llevar esto a cabo son:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
• Esta función inicializa un mutex. Hay que llamarla antes de usar cualquiera de las funciones que trabajan
con mutex.
• mutex: Es un puntero a un parámetro del tipo pthread_mutex_t, que es el tipo de datos que usa la librería
Pthreads para controlar los mutex.
• attr: Es un puntero a una estructura del tipo pthread_mutexattr_t, y sirve para definir qué tipo de mutex
queremos: normal, recursivo o errorcheck (esto se verá más adelante)
Si este valor es NULL (recomendado), la librería le asignará un valor por defecto.
• La función devuelve 0 si se pudo crear el mutex o -1 si hubo algún error.
int pthread_mutex_lock(pthread_mutex_t *mutex)
• Esta función pide el bloqueo para entrar en una RC. Si queremos implementar una RC, todos los thread
tendrán que pedir el bloqueo sobre el mismo semáforo.
• mutex: Es un puntero al mutex sobre el cual queremos pedir el bloqueo o sobre el que nos bloquearemos
en caso de que ya haya alguien dentro de la RC.
• Como resultado, devuelve 0 si no hubo error, o diferente de 0 si lo hubo.
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 4

int pthread_mutex_unlock(pthread_mutex_t *mutex)


• Esta es la función contraria a la anterior. Libera el bloqueo que tuviéramos sobre un semáforo.
• mutex: Es el semáforo donde tenemos el bloqueo y queremos liberarlo.
• Retorna 0 como resultado si no hubo error o diferente de 0 si lo hubo.
int pthread_mutex_destroy(pthread_mutex_t *mutex)
• Le dice a la librería que el mutex que le estamos indicando no lo vamos a usar más, y que puede liberar
toda la memoria ocupada en sus estructuras internas por ese mutex.
• mutex: El mutex que queremos destruir.
• La función, como siempre, devuelve 0 si no hubo error, o distinto de 0 si lo hubo.
Estas son las funciones más básicas. Ahora, reescribiremos el pseudocódigo del ejemplo anterior con lo que
hemos visto hasta ahora.

Variables globales:
pthread_mutex_t mutex_acceso;
int i;

Hilo 1 (Versión correcta)


void *funcion_hilo_1(void *arg)
{
int resultado;
...
pthread_mutex_lock(&mutex_acceso);
if (i == valor_cualquiera) {
... <
resultado = i * (int)*arg;
... <
}
pthread_mutex_unlock(&mutex_acceso);
pthread_exit(&resultado);
}

Hilo 2 (Versión correcta)


void *funcion_hilo_2(void *arg)
{
int otro_resultado;
...
if (funcion_sobre_arg(*arg) == 0) {
...
pthread_mutex_lock(&mutex_acceso);
i = *arg;
pthread_mutex_unlock(&mutex_acceso);
...
}
pthread_exit(&otro_resultado);
}

int main(void)
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 5

{
...
pthread_mutex_init(&mutex_acceso, NULL);
...
}

En color azul han sido añadidas las líneas que antes no estaban.
Como se puede ver lo único que hay que hacer es inicializar el semáforo, pedir el bloqueo antes de las RC y
liberarlo después de salir de la RC, aunque a veces es cuestión también de tener un poco de vista.
Contra más pequeñas hagamos las RC, más concurrentes serán nuestros programas, porque tendrán que
esperar menos tiempo en el caso de que haya bloqueos.

Deadlocks

Aunque esto realmente soluciona el problema de los accesos concurrentes, también nos puede traer más
problemas.
Y los problemas aquí también tienen nombre: los Deadlocks (o Abrazos Mortales) Los Deadlocks se producen
cuando un hilo se bloquea esperando un recurso que tiene bloqueado otro hilo que está esperando un
recurso. Si el recurso para el segundo thread no llega nunca, no se desbloqueará nunca, con lo cual tampoco
se desbloqueará nunca el primer thread.
Resultado: nuestro fantástico programa bloqueado.
Solución: Pues aunque la librería de Pthreads nos de algún mecanismo para intentar prevenir que esto se
produzca, no hay ningún mecanismo fiable al 100% para prevenirlos.
El modelo más sencillo de Deadlock es el circular:

Hilo 1
void *funcion_hilo_1(void *arg)
{
...
pthread_mutex_lock(&mutex_1);
...
pthread_mutex_unlock(&mutex_2);
...
}

Hilo 2
void *funcion_hilo_2(void *arg)
{
...
pthread_mutex_lock(&mutex_2);
...
pthread_mutex_unlock(&mutex_1);
...
}
II. EJERCICIO RESUELTO
Ejercicio 1.
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 6

Crear dos threads en un programa en C utilizando pthread, guardar el programa con el nombre de
ejercicio01.c:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

pthread_t tid[2];
int counter;

void* trythis(void* arg)


{
unsigned long i = 0;
counter += 1;
printf("\n El trabajo %d ha empezado\n", counter);

for (i = 0; i < (0xFFFFFFFF); i++)


;
printf("\n El trabajo %d ha finalizado\n", counter);

return NULL;
}

int main(void)
{
int i = 0;
int error;

while (i < 2) {
error = pthread_create(&(tid[i]), NULL, &trythis, NULL);
if (error != 0)
printf("\nThread no puede ser creado : [%s]", strerror(error));
i++;
}

pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);

return 0;
}

Para compilar este programa utilizamos el siguiente comando en línea de comandos

$ gcc -w ejercicio01.c -lpthread -o ejercicio01


UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 7

Ejercicio 2.
Crear dos threads en un programa en C utilizando pthread, guardar el programa con el nombre de
ejercicio02.c:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

pthread_t tid[2];
int counter;
pthread_mutex_t lock;

void* trythis(void* arg)


{
pthread_mutex_lock(&lock);
unsigned long i = 0;
counter += 1;
printf("\n El trabajo %d ha empezado\n", counter);
for (i = 0; i < (0xFFFFFFFF); i++)
;
printf("\n El trabajo %d ha finalizado\n", counter);
pthread_mutex_unlock(&lock);
return NULL;
}

int main(void)
{
int i = 0;
int error;
if (pthread_mutex_init(&lock, NULL) != 0) {
printf("\n el inicio de mutex ha fallado\n");
return 1;
}
while (i < 2) {
error = pthread_create(&(tid[i]),
NULL,
&trythis, NULL);
if (error != 0)
printf("\nThread can't be created :[%s]",
strerror(error));
i++;
}
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
pthread_mutex_destroy(&lock);
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 8

return 0;
}

Para compilar este programa utilizamos el siguiente comando en línea de comandos

$ gcc -w ejercicio02.c -lpthread -o ejercicio02

Ejercicio 3.
Crear dos threads en un programa en C utilizando pthread, guardar el programa con el nombre de
ejercicio03.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

char s1[] = "abcdefg";


char s2[] = "abc";

pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;


// Intente descomentar y comentar el texto mutexto a continuación.
// y observe la salida

void print(char* a, char* b) {


pthread_mutex_lock(&mutex1); // comentar
printf("1: %s\n", a);
sleep(1);
printf("2: %s\n", b);
pthread_mutex_unlock(&mutex1); // comentar
}

// Estas dos funciones se ejecutarán simultáneamente.


void* print_i(void *ptr) {
print("I am", " in i");
}

void* print_j(void *ptr) {


print("I am", " in j");
}

int main() {
pthread_t t1, t2;
int iret1 = pthread_create(&t1, NULL, print_i, NULL);
int iret2 = pthread_create(&t2, NULL, print_j, NULL);

while(1){}
exit(0); //nunca alcanzado
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 9

Para compilar este programa utilizamos el siguiente comando en línea de comandos

$ gcc ejercicio03.c -lpthread -o ejercicio03

Ejercicio 4.
Crear el siguiente programa en c, donde se mostrará en orden los mensajes de las funciones T1 y T2, usando
la cerradura mutex

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

pthread_mutex_t ml;

void* Test(char* p, char* q) {


pthread_mutex_lock(&ml);
printf("%s...\n", p);
sleep(5);
printf("%s...\n", q);
sleep(5);
pthread_mutex_unlock(&ml);
}

void* T1(void* z) {
Test("Inicializado", "1er Thread"); }
void* T2(void* z) {
Test("Inicializado ", "2do Thread"); }

int main() {
pthread_t t1, t2;
pthread_create(&t1, NULL, &T1, NULL);
pthread_create(&t2, NULL, &T2, NULL);
while(1) {}
exit(0);
}

Para compilar este programa utilizamos el siguiente comando en línea de comandos

$ gcc ejercicio04.c -lpthread -o ejercicio04

Ejercicio 5.
Crear el siguiente programa en c, donde se presenta en orden los mensajes creados por cada thread,
guárdelo como ejercicio05.c
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 10

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif

int shared = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* func3(void* param) {


pthread_mutex_lock(&mutex);
printf("Incrementing the shared variable...\n");
for (int i = 0; i < 10000; ++i) {
shared += 1;
}
pthread_mutex_unlock(&mutex);
return 0;
}

int main() {
pthread_t threads[NUM_THREADS];

for (int i = 0; i < NUM_THREADS; ++i) {


pthread_create(&threads[i], NULL, func3, NULL);
}

for (int i = 0; i < NUM_THREADS; ++i) {


pthread_join(threads[i], NULL);
}

printf("%d\n", shared);
exit(EXIT_SUCCESS);
}

Para compilar este programa utilizamos el siguiente comando en línea de comandos

$ gcc ejercicio05.c -lpthread -o ejercicio05

Ejercicio 6.
Crear el siguiente programa en c, este programa crea dos archivos utlizando la función fopen() y fclose(),
llamelo ejercicio06.c, compílelo

# include <stdio.h>
# include <stdlib.h>
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 11

# include <pthread.h>
# include <ctype.h>
int total_words ;
pthread_mutex_t counter_lock = PTHREAD_MUTEX_INITIALIZER ;
int main (int ac , char *av[])
{ pthread_t t1 , t2 ;
void *count_words(void *);
if ( ac != 3 ) {
printf("usage : %s file1 file2 \n" , av[0]) ;
exit(1); }
total_words =0;
pthread_create(&t1 , NULL, count_words, (void *)av[1]) ;
pthread_create(&t2 , NULL, count_words, (void *)av[2]) ;
pthread_join(t1 , NULL);
pthread_join(t2 , NULL);
printf("Main thread wirth ID % ld reporting %5 d total words \n ", pthread_self(), total_words);
}
void *count_words (void *f)
{
char *filename = (char *)f;
FILE *fp ; int c , prevc = '\0 ';
if ( ( fp = fopen ( filename ,"r") ) != NULL ){
while ( ( c = getc ( fp ) ) != EOF ){
if ( ! isalnum ( c) && isalnum ( prevc ) ){
pthread_mutex_lock(&counter_lock ) ;
total_words ++;
pthread_mutex_unlock(&counter_lock );
}
prevc = c;
}
fclose(fp);
} else perror(filename);
return NULL ;
}

Para compilar este programa utilizamos el siguiente comando en línea de comandos

$ gcc ejercicio06.c -lpthread -o ejercicio06

Ejercicio 7
Crear el siguiente programa en c, que cancela la ejecución de un thread usando la función cancel(), llamelo
ejercicio07.c, compílelo

#include<pthread.h>
#include<stdio.h>
#include<unistd.h>
void *fun1();
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 12

void *fun2();
int shared=1; //variable compartida
pthread_mutex_t l; //mutex lock
int main()
{
pthread_mutex_init(&l, NULL); //inicializando mutex locks
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, fun1, NULL);
pthread_create(&thread2, NULL, fun2, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2,NULL);
printf("El valor final de la variable compartida es %d\n",este); //imprime la ultima actualización del valor de
la variable compartida
}
void *fun1()
{
int x;
printf("Thread1 intentando adquirir la cerradura \n");
pthread_mutex_lock(&l);
//thread uno adquiriendo la cerradura. Ahora los otros threads no serán capacesde de adquirir la cerradura
//hasta que sea liberado por el threada 1
printf("Thread1 adquiere la cerradura\n");
x=shared;//el thread lee el valor de la variable compartida
printf("Thread1 lee el valor de la variable compartida %d\n",x);
x++; //thread uno incremente al valor
printf("Actualizacionón local del Thread1: %d\n",x);
sleep(1); //thread uno es prevenido por thread 2
shared=x; //thread uno actualiza el valor de la variable compartida
printf("Valor de la variable compartida actualizada del Thread1 es: %d\n",shared);
pthread_mutex_unlock(&l);
printf("Thread1 libera la cerradura \n");
return NULL;
}
void *fun2()
{
int y;
printf("Thread2 intenta adquiriri la cerradura \n");
pthread_mutex_lock(&l);
printf("Thread2 adquiere la cerradura \n");
y=shared;//thread dos lee el valor de la variable compartida
printf("Thread2 lee el valor de %d\n",y);
y--; //thread two incrementa el valor
printf("Actualización Local del Thread2: %d\n",y);
sleep(1); //thread dos es prevenido por thread 1
shared=y; //thread uno es actualiza el valor de la variable compartida
printf("Valor de la variable compartida actualizado por el Thread2 es: %d\n",shared);
pthread_mutex_unlock(&l);
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 13

printf("Thread2 libera la cerradura \n");


return NULL;
}

Para compilar este programa utilizamos el siguiente comando en linea de comandos

$ gcc ejercicio07.c -lpthread -o ejercicio07

Ejercicio 8.
Crear el siguiente programa en c, que implementa un deadlock, llamelo ejercicio08.c, compílelo

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>

pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;


pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;

// Estas dos funciones corren concurrentemente.


void* print_i(void *ptr) {
pthread_mutex_lock(&mutex1);
pthread_mutex_lock(&mutex2);
printf("I am in i");
pthread_mutex_unlock(&mutex2);
pthread_mutex_unlock(&mutex1);
}

void* print_j(void *ptr) {


pthread_mutex_lock(&mutex2);
pthread_mutex_lock(&mutex1);
printf("I am in j");
pthread_mutex_unlock(&mutex1);
pthread_mutex_unlock(&mutex2);
}

int main() {
pthread_t t1, t2;
int iret1 = pthread_create(&t1, NULL, print_i, NULL);
int iret2 = pthread_create(&t2, NULL, print_j, NULL);

while(1){}
exit(0); //nunca alcanzado.
}
Para compilar este programa utilizamos el siguiente comando en linea de comandos
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 14

$ gcc ejercicio08.c -pthread -o ejercicio08

Ejercicio 9
Crear el siguiente programa en c, que coordina más de dos threads, llamelo ejercicio09.c, compílelo

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>

int mails = 0;
pthread_mutex_t mutex;

void* routine() {
for (int i = 0; i < 10000000; i++) {
pthread_mutex_lock(&mutex);
mails++;
pthread_mutex_unlock(&mutex);
// lee mails
// incrementa
// escribe mails
}
}

int main(int argc, char* argv[]) {


pthread_t p1, p2, p3, p4;
pthread_mutex_init(&mutex, NULL);
if (pthread_create(&p1, NULL, &routine, NULL) != 0) {
return 1;
}
if (pthread_create(&p2, NULL, &routine, NULL) != 0) {
return 2;
}
if (pthread_create(&p3, NULL, &routine, NULL) != 0) {
return 3;
}
if (pthread_create(&p4, NULL, &routine, NULL) != 0) {
return 4;
}
if (pthread_join(p1, NULL) != 0) {
return 5;
}
if (pthread_join(p2, NULL) != 0) {
return 6;
}
if (pthread_join(p3, NULL) != 0) {
return 7;
}
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 15

if (pthread_join(p4, NULL) != 0) {
return 8;
}
pthread_mutex_destroy(&mutex);
printf("Numero de mails: %d\n", mails);
return 0;
}

Para compilar este programa utilizamos el siguiente comando en linea de comandos

$ gcc ejercicio09.c -lpthread -o message_send

Ejercicio 10
Crear el siguiente programa en c, que compara dos threads, llamelo ejercicio10.c, compílelo

#include <stdio.h>
#include <pthread.h>

// Cada thread cuenta TIMES_TO_COUNT veces


#define TIMES_TO_COUNT 21000

#define NC "\e[0m"
#define YELLOW "\e[33m"
#define BYELLOW "\e[1;33m"
#define RED "\e[31m"
#define GREEN "\e[32m"

// Esta estructura contiene el recuento así como el mutex


// eso protegerá el acceso a la variable.
typedef struct s_counter
{
pthread_mutex_t count_mutex;
unsigned int count;
} t_counter;

void *thread_routine(void *data)


{
// Cada thread empieza aqui
pthread_t tid;
t_counter *counter; // puntero a la estructura en main
unsigned int i;

tid = pthread_self();
counter = (t_counter *)data;
// Imprime el recuento antes de que este hilo comience a iterar.
// Para leer el valor de count, bloqueamos el mutex:
pthread_mutex_lock(&counter->count_mutex);
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 16

printf("%sThread [%ld]: contador del thread empieza = %u.%s\n",


YELLOW, tid, counter->count, NC);
pthread_mutex_unlock(&counter->count_mutex);
i = 0;
while (i < TIMES_TO_COUNT)
{
// Iterar TIMES_TO_COUNT veces
// Incrementa el contador en cada iteración
// Bloquear el mutex mientras dure el incremento
pthread_mutex_lock(&counter->count_mutex);
counter->count++;
pthread_mutex_unlock(&counter->count_mutex);
i++;
}
// Imprime el recuento final cuando este hilo termina su
// cuenta propia, sin olvidar bloquear el mutex:
pthread_mutex_lock(&counter->count_mutex);
printf("%sThread [%ld]: Contador final = %u.%s\n",
BYELLOW, tid, counter->count, NC);
pthread_mutex_unlock(&counter->count_mutex);
return (NULL); // Thread termine ici.
}

int main(void)
{
pthread_t tid1;
pthread_t tid2;
// Esta estructura continene el contador total del thread
t_counter counter;

// Aquí solo hay un hilo (hilo principal), por lo que podemos hacerlo de forma segura
// inicializa el recuento sin utilizar el mutex.
counter.count = 0;
// Inicializa el mutex :
pthread_mutex_init(&counter.count_mutex, NULL);
// Dado que cada hilo cuenta TIMES_TO_COUNT veces y eso
// tenemos 2 hilos, esperamos que el recuento final sea
// 2 * VECES_PARA_CONTAR:
printf("Main: el contador esperado es %s%u%s\n", GREEN,
2 * TIMES_TO_COUNT, NC);
// Creación del Thread:
pthread_create(&tid1, NULL, thread_routine, &counter);
printf("Main: Creando el primer thread [%ld]\n", tid1);
pthread_create(&tid2, NULL, thread_routine, &counter);
printf("Main: Creando el segundo thread [%ld]\n", tid2);
// Thread adicionado:
pthread_join(tid1, NULL);
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 17

printf("Main: adiciona el primer thread [%ld]\n", tid1);


pthread_join(tid2, NULL);
printf("Main: adiciona el segundo thread [%ld]\n", tid2);
// Contador final de la evaluación:
// (Aquí podemos leer el conteo sin preocuparnos
// el mutex porque todos los hilos se han unido y
// no puede haber carrera de datos entre hilos)
if (counter.count != (2 * TIMES_TO_COUNT))
printf("%sMain: ERROR ! Total contador es %u%s\n",
RED, counter.count, NC);
else
printf("%sMain: OK. Total contador es %u%s\n",
GREEN, counter.count, NC);
// Destruye el mutex al final del programa:
pthread_mutex_destroy(&counter.count_mutex);
return (0);
}

Para compilar este programa utilizamos el siguiente comando en linea de comandos

$ gcc ejercicio10.c -lpthread -o ejercicio10

III. EJERCICIOS PROPUESTOS


Ejercicio 1. Dado el siguiente código
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NTHREADS 4
int contador=0;
2
EI1014/MT1014 Bolet´ın 3.1
void *hilo(void *arg)
{
int i;
i = (int) arg;
contador = contador + i;
printf("Hilo %u, contador = %u\n",pthread_self(),contador);
pthread_exit(0);
}
int main()
{
int i;
pthread_t thread[NTHREADS]; //vector para definir los hilos
for (i=0;i<NTHREADS;i++)
{ pthread_create(&thread[i], NULL, hilo, (void *)i);
pthread_join(thread[i],NULL);
}
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 18

printf("Hilo principal, contador = %d\n",contador);


pthread_exit (0);
}

¿Cuántos lock mutex son necesarios para sincroninar los hilos?, impleméntelo

Ejercicio 2. Modifique el código del ejercicio 10 para que ejecute 4 threads

Ejercicio 3. Cree un programa basado en el ejercicio 09 que permita la sincronización de 10 hilos

IV. CUESTIONARIO
1. ¿Qué hace la función pthread_mutex_trylock de la librería pthread?
2. ¿Un semáforo es lo mismo que un lock mutex?

V. REFERENCIAS Y BIBLIOGRÁFIA RECOMENDADAS:


[1] PUCP. 29 de Mayo 2007 Laboratorio 4: Hilos POSIX (Thread POSIX: pthreads): online, Available:
http://inform.pucp.edu.pe/~inf232/Semestre-2007-1/Laboratorio-4/index.htm

TÉCNICAS E INSTRUMENTOS DE EVALUACIÓN


TÉCNICAS: INSTRUMENTOS:
Ejercicios propuestos Rubricas

CRITERIOS DE EVALUACIÓN Y LOGROS ALCANZADOS


Criterio de 1 = Insatisfactorio 2 = En proceso 3 = Satisfactorio 4 = Sobresaliente
evaluación/
Niveles de
Expectativa
Informe El informe es difícil
El informe incluye la El informe incluye El informe está
de leer y no cuenta
mayor parte de la la información claramente detallado e
con la informacióninformación solicitada, solicitada y es incluye toda la
pedida (0) pero cuesta comprenderlo comprensible (4) información solicitada
(2) (8)
Cantidad de Uno o más de los Todos los temas han sido Todos los temas Todos los temas han
Información temas no han sido tratados y la mayor parte han sido tratados sido tratados y todas las
tratados (0) de las preguntas han sido y la mayor parte preguntas han sido
contestadas, como de las preguntas contestadas con tres o
mínimo, con una frase (2) han sido más frases cada una (6)
UNIVERSIDAD NACIONAL DE SAN AGUSTIN
FACULTAD DE INGENIERÍA DE PRODUCCIÓN Y SERVICIOS
ESCUELA PROFESIONAL DE INGENIERÍA DE SISTEMA

Formato: Guía de Práctica de Laboratorio / Talleres / Centros de Simulación


Aprobación: 2022/03/01 Código: GUIA-PRLD-001 Página: 19

contestadas,
como mínimo con
dos frases cada
una (3)
Calidad de La información La información está La información La información está
información tiene poco que ver relacionada con el tema está claramente claramente relacionada
con el tema principal (2) relacionada con el con el tema principal y
principal (0) tema principal (3) presenta otros ejemplos
(6)
Calidad del No cumplió con El ejercicio fue Se llega a una Se llega a una solución
ejercicio realizar el ejercicio desarrollado pero no se solución utilizando del
planteado(0) llego a una solución o al utilizando el procedimiento sugerido
objetivo pedido(2) procedimiento en pocas líneas de
sugerido(3) código(4)

También podría gustarte