0% encontró este documento útil (0 votos)
11 vistas46 páginas

Programación de Hilos POSIX

El documento trata sobre la programación con hilos utilizando el estándar POSIX y la biblioteca PThreads. Se abordan temas como la identificación, creación, bloqueo, y terminación de hilos, así como ejemplos prácticos de su implementación. Además, se discuten las diferencias entre las funciones de finalización de hilos y los tipos de hilos (detached y joinable).
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
11 vistas46 páginas

Programación de Hilos POSIX

El documento trata sobre la programación con hilos utilizando el estándar POSIX y la biblioteca PThreads. Se abordan temas como la identificación, creación, bloqueo, y terminación de hilos, así como ejemplos prácticos de su implementación. Además, se discuten las diferencias entre las funciones de finalización de hilos y los tipos de hilos (detached y joinable).
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

Tema 2.

Programación con hilos

Antonio Molina Picó


13 de febrero de 2024
Índice
1.1. Estándar POSIX
Capítulo 1 1.2. PThreads
Introducción

2.1. Identificación de hilos


2.2. Creación
Capítulo 2.
2.3. Bloqueo o espera a la finalización de hilos
Operaciones 2.4. Terminación
2.5. Atributos (configuración)

Capítulo 3.
3.1. Caracoles
Ejemplo
Índice
1.1. Estándar POSIX
Capítulo 1 1.2. PThreads
Introducción

2.1. Identificación de hilos


2.2. Creación
Capítulo 2.
2.3. Bloqueo o espera a la finalización de hilos
Operaciones 2.4. Terminación
2.5. Atributos (configuración)

Capítulo 3.
3.1. Caracoles
Ejemplo
Estándar POSIX (Portable Operating System Interface)
Es un estándar orientado a facilitar la creación de aplicaciones
fiables y portables. La mayoría de las versiones de UNIX cumplen con
este estándar.
¿En qué sección de las
Pthreads (POSIX threads) páginas del manual?
Biblioteca para el manejo de hilos en POSIX

#include <pthread.h>

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


pthread_t hilo;

return 0;
}
Índice
1.1. Estándar POSIX
Capítulo 1 1.2. PThreads
Introducción

2.1. Identificación de hilos


2.2. Creación
Capítulo 2.
2.3. Bloqueo o espera a la finalización de hilos
Operaciones 2.4. Terminación
2.5. Atributos (configuración)

Capítulo 3.
3.1. Caracoles
Ejemplo
Identificación de hilos

Identificación
Los hilos se identifican con el tipo pthread_t. Este tipo de datos es
una estructura transparente al usuario, que dependiendo de la
implementación puede contener información adicional.

#include <pthread.h>

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


pthread_t hilo; // TID hilo, de tipo pthread_t

return 0;
}
Identificación de hilos

Identificación
¿Creéis que podemos hacer algo como lo siguiente para saber si
estos dos identificadores corresponden al mismo hilo?

#include <pthread.h>
int main(void argc, char *argv[]){
pthread_t hilo1;
pthread_t hilo2;

if (hilo1 == hilo2){
}
return 0;
}
Identificación de hilos

Identificación
Funciones para gestionar los identificadores de los hilos

pthread_self devuelve el TID del hilo que lo invoca


#include <pthread.h>
pthread_t pthread_self(void);

pthread_equal compara dos TIDs. Devuelve 0 si no son iguales y


otro valor si son idénticos.
#include <pthread.h>
int pthread_equal(pthread_t th1, pthread_t th2);
Índice
1.1. Estándar POSIX
Capítulo 1 1.2. PThreads
Introducción

2.1. Identificación de hilos


2.2. Creación
Capítulo 2.
2.3. Bloqueo o espera a la finalización de hilos
Operaciones 2.4. Terminación
2.5. Atributos (configuración)

Capítulo 3.
3.1. Caracoles
Ejemplo
Creación de hilos
int pthread_create(....); A nivel de programación

rv = pthread_create();
A nivel de SO
Creación del TCB, actualización de punteros,
reserva de memoria para la pila privada ¿rv=0?
No Si

pthread_create
ERROR OK

HILO a
READY
Creación de hilos

Creación
Muchos más argumentos que el fork.

#include <pthread.h>
int pthread_create( pthread_t *thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *),
void *arg);

thread → puntero al TID del hilo declarado


attr → atributos/características del hilo
start_routine → la función que ejecutará el hilo
arg → puntero a argumentos que se le pueden pasar
#include <stdio.h>

Ejemplo
#include <pthread.h>
void *funcion(void *p) {
printf("Función que ejecuta el hilo creado!\n");
}
int main (void) {
pthread_t id_hilo;
printf("Hilo principal: Empiezo!\n");
pthread_create(&id_hilo, NULL, funcion, NULL);
printf("Hilo principal: He creado un hilo\n");
return 0;
}

¿Cuántos hilos se están ejecutando concurrentemente?


¿Qué printf se imprime antes: “Funcion” o “He creado”?
¿El hilo principal es el padre del hilo id_hilo?
Creación de hilos. Paso de argumentos al hilo.

Creación
pthread_create(<tid>,<attr>,<funcion>,<ARGS>)

#include <stdio.h>
#include <pthread.h>
void *funcion(void *p) {
¿Qué líneas

printf("Soy el hilo: %d\n", val);
tenemos
}
int main (void) {
que añadir
pthread_t id_hilo;
printf("Hilo principal: Empiezo!\n"); para que
pthread_create(&id_hilo, NULL, funcion, 1);
return 0; imprima ok?
}
Creación de hilos. Paso de argumentos al hilo.

Creación
pthread_create(<tid>,<attr>,<funcion>,<ARGS>)

#include <stdio.h>
#include <pthread.h>
void *funcion(void *p) {
Solucion 1
int val=*(int *)p;
printf("Soy el hilo: %d\n", val);
}
int main (void) {
int val=1;
pthread_t id_hilo;
printf("Hilo principal: Empiezo!\n");
pthread_create(&id_hilo, NULL, funcion, (void *)&val);
sleep(1);
return 0;
}
Creación de hilos. Paso de argumentos al hilo.

Creación
pthread_create(<tid>,<attr>,<funcion>,<ARGS>)

#include <stdio.h>
#include <pthread.h>
void *funcion(void *p) {
Solucion 2
int val=(int)p;
printf("Soy el hilo: %d\n", val);
}
int main (void) {
pthread_t id_hilo;
printf("Hilo principal: Empiezo!\n");
pthread_create(&id_hilo, NULL, funcion, (void *) 1);
sleep(1);
return 0;
}
Creación de hilos. Valores de retorno erróneos

Creación
#include <error.h>
int pthread_create(...)

Devuelve 0 si se crea correctamente o otro valor si ocurre un error.

EAGAIN → No hay recursos para crear el thread


cat /proc/sys/kernel/threads-max

EINVAL → Atributos inválidos pasados como argumentos

EPERM → Sin permisos para establecer los atributos establecidos


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

void *funcion(void *p) {


printf("Función que ejecuta el hilo creado!\n");
}

int main (void) {


pthread_t id_hilo;
printf("Hilo principal: Empiezo!\n");
if (rv=pthread_create(&id_hilo, NULL, funcion, NULL) != 0) {
perror(“Fallo al crear el thread. Error:%d\n”,rv);
return 1;
}
printf("Hilo principal: He creado un hilo\n");
return 0;
}
Creación de hilos

Ejemplo
Aspectos a tener en cuenta
1. Una vez creado, el hijo pasa automáticamente al
estado PREPARADO y se ejecuta en el procesador
cuando el PLANIFICADOR así lo decida
2. El hilo que ejecuta el main, se trata de un hilo más
del proceso y así debe contabilizarse. No es el padre.
3. La llamada pthread_create puede ser invocada por
cualquier hilo, no solo por el hilo principal
Índice
1.1. Estándar POSIX
Capítulo 1 1.2. PThreads
Introducción

2.1. Identificación de hilos


2.2. Creación
Capítulo 2.
2.3. Bloqueo o espera a la finalización de hilos
Operaciones 2.4. Terminación
2.5. Atributos (configuración)

Capítulo 3.
3.1. Caracoles
Ejemplo
Espera a la finalización de hilos

Espera
Detached: Libera los recursos (TCB) cuando
Los hilos pueden ser termina
de dos tipos Joinable: Espera a liberar los recursos a que
lo diga otro hilo (opción por defecto)

#include <pthread.h>
int pthread_join(pthread_t th, void **rval);

th → puntero al hilo que esperamos a que termine


rval → valor de retorno
Espera a la finalización de hilos. Valores de retorno.

Creación
#include <error.h>
int pthread_join(pthread_t th, void **rval);

Devuelve 0 si se ejecuta OK, devuelve un número != 0 si ERROR.

EDEADLK → Ya hay un join a ese thread

EINVAL → El thread no es de tipo joinable

ESRCH → El TID del thread no se puede encontrar


#include <stdio.h>

Ejemplo
#include <pthread.h>

void *funcion(void *p) {


printf("Función que ejecuta el hilo creado!\n");
}

int main (void) {


pthread_t id_hilo;
printf("Hilo principal: Empiezo!\n");
pthread_create(&id_hilo, NULL, funcion, NULL);
printf("Hilo principal: He creado un hermano al que espero\n");
pthread_join(id_hilo,NULL);
printf("Hilo principal: Termino!\n");
}

¿Cuál va a ser el orden de las impresiones por consola?


¿Pueden existir hilos huérfanos o zombis?
Espera a la finalización de hilos

Espera
Obtener un valor de retorno
#include <stdio.h>
#include <pthread.h> ¿Este
#include <stdlib.h>
#include <time.h> código
void *tirar_dado(void *p) {
int valor = (rand()%6)+1;
creéis que
}
return (void *)&valor; va a
int main (void) {
int *res;
funcionar?
srand(time(NULL));
pthread_t th;
pthread_create(&th, NULL, &tirar_dado, NULL);
¿Alguna
pthread_join(th, (void **)&res);
printf("Valor:%d\n",*res);
solución?
}
Espera a la finalización de hilos

Espera
Obtener un valor de retorno
int valor; // GLOBAL
void *tirar_dado(void *p) { Solucion 1
valor = (rand()%6)+1;
return 0;
}
int main (void) {
¿Alguna
int *res;
srand(time(NULL)); otra
pthread_t th;
pthread_create(&th, NULL, &tirar_dado, NULL); solución?
pthread_join(th, NULL);
printf("Valor:%d\n",valor);
}
Espera a la finalización de hilos

Espera
Obtener un valor de retorno

void *tirar_dado(void *p) { Solucion 2


int valor = (rand()%6)+1;
int *resultado = malloc(sizeof(int)); //HEAP
*resultado=valor;
return (void *)resultado;
}

int main (void) {


int *res;
srand(time(NULL));
pthread_t th;
pthread_create(&th, NULL, &tirar_dado, NULL);
pthread_join(th, (void **)&res);
printf("Valor:%d\n",*res);
free(res);
}
Espera a la finalización de hilos

Espera
Detached: Libera los recursos (TCB) cuando
Los hilos pueden ser termina
de dos tipos Joinable: Espera a liberar los recursos a que
lo diga otro hilo (opción por defecto)

#include <pthread.h>
int pthread_detach(pthread_t *th);

th → puntero al hilo que lo convertimos en detached


Un hilo puede ser creado de tipo detached al crearse mediante los
atributos, en el hilo main o en la ejecución del propio hilo con:
pthread_detach(pthread_self());
Espera a la finalización de hilos

Espera
#include <stdio.h>
#include <pthread.h> ¿Qué se
#include <unistd.h>
void *funcion(void *p) { imprime?
sleep(1);
printf("Función que ejecuta el hilo creado!\n");
}
int main (void) {
pthread_t id_hilo;
printf("Hilo principal: Empiezo!\n");
pthread_create(&id_hilo, NULL, funcion, NULL);
pthread_detach(id_hilo)
if (pthread_join(id_hilo,NULL) != 0){
perror(“Ha fallado el join\n”); return 0;
};
printf("Hilo principal: Termino!\n");
return 0;
}
Índice
1.1. Estándar POSIX
Capítulo 1 1.2. PThreads
Introducción

2.1. Identificación de hilos


2.2. Creación
Capítulo 2.
2.3. Bloqueo o espera a la finalización de hilos
Operaciones 2.4. Terminación
2.5. Atributos (configuración)

Capítulo 3.
3.1. Caracoles
Ejemplo
Terminación de hilos

Terminación
1. Acaba las instrucciones a ejecutar
2. Finaliza de manera voluntaria
Un hilo puede finalizar si:
3. Le invitan a que finalice
4. El proceso termina.

#include <pthread.h>
void pthread_exit(void *retval); → VOLUNTARIA
int pthread_cancel(pthread_t th); → INVITACIÓN
Diferencias entre return, exit and pthread_exit
Mismo comportamiento en un hilo distinto al principal. ¿Resultado de los print?

void *tirar_dado(void *p) { void *tirar_dado(void *p) {


int valor = (rand()%6)+1; int valor = (rand()%6)+1;
int *resultado = malloc(sizeof(int)); int *resultado = malloc(sizeof(int));
*resultado=valor; *resultado=valor;
printf("Thread Valor:%d\n",*res); printf("Thread valor:%d\n",*res);
return (void *)resultado; pthread_exit((void *)resultado);
} }
int main (void) { int main (void) {
int *res; int *res;
srand(time(NULL)); srand(time(NULL));
pthread_t th; pthread_t th;
pthread_create(&th, NULL, pthread_create(&th, NULL,
&tirar_dado, NULL); &tirar_dado, NULL);
pthread_join(th, (void **)&res); pthread_join(th, (void **)&res);
printf("Main valor:%d\n",*res); printf("Main valor:%d\n",*res);
free(res); free(res);
} }
Diferencias entre return, exit and pthread_exit
¿Qué ocurre ahora con los prints?

void *tirar_dado(void *p) { Seguro que no se


int valor = (rand()%6)+1;
int *resultado = malloc(sizeof(int));
imprime el print del
*resultado=valor; main y es muy
printf("Thread Valor:%d\n",*res); probable que tampoco
return (void *)resultado; el del thread.
}
int main (void) {
int *res; Al finalizar el proceso
srand(time(NULL)); con exit o return, se
pthread_t th; matan todos los hilos
pthread_create(&th, NULL, &tirar_dado, NULL);
return 0; // exit(0); de ejecución.
pthread_join(th, (void **)&res);
printf("Main valor:%d\n",*res);
free(res);
}
Diferencias entre return, exit and pthread_exit
Y si se ejecuta pthread_exit en el hilo principal, ¿qué ocurre con los prints?

void *tirar_dado(void *p) { El hilo principal al


int valor = (rand()%6)+1;
int *resultado = malloc(sizeof(int));
encontrarse un
*resultado=valor; pthread_exit no
printf("Thread Valor:%d\n",*res); ejecutará ninguna
return (void *)resultado; instrucción posterior,
}
int main (void) {
pero no termina el
int *res; proceso. Se esperará
srand(time(NULL)); hasta que finalicen los
pthread_t th; hilos creados.
pthread_create(&th, NULL, &tirar_dado, NULL);
pthread_exit(0);
pthread_join(th, (void **)&res);
printf("Main valor:%d\n",*res);
free(res);
}
Terminación de hilos

Terminación
1. Acaba las instrucciones a ejecutar
2. Finaliza de manera voluntaria
Un hilo puede finalizar si:
3. Le invitan a que finalice
4. El proceso termina.

#include <pthread.h>
void pthread_exit(void *retval); → VOLUNTARIA
int pthread_cancel(pthread_t th); → INVITACIÓN

Al igual que con return, debe seguir


existiendo cuando el hilo haya
finalizado: o global o heap
Índice
1.1. Estándar POSIX
Capítulo 1 1.2. PThreads
Introducción

2.1. Identificación de hilos


2.2. Creación
Capítulo 2.
2.3. Bloqueo o espera a la finalización de hilos
Operaciones 2.4. Terminación
2.5. Atributos (configuración)

Capítulo 3.
3.1. Caracoles
Ejemplo
Atributos de los hilos (propiedades)

Terminación
#include <pthread.h>
void pthread_attr_init(pthread_attr_t *attr);
void pthread_attr_destroy(pthread_attr_t *attr);

attr es un puntero a los atributos de un hilos


● Se deben iniciar y destruir si se quiere modificar alguno de
los atributos que disponen los hilos por defecto
● Se pueden crear múltiples hilos con dichos atributos (misma
variable attr)
● Se modifican con funciones específicas
Atributos de los hilos: TIPO DE HILO

Terminación
#include <pthread.h>
int pthread_attr_setdetachstate( pthread_attr_t *attr,
int detachstate);
int pthread_attr_getdetachstate( pthread_attr_t *attr,
int *detachstate);

Establecer si son de tipo DETACHED o JOINABLES.


El argumento detachstate puede establecerse a:
● PTHREAD_CREATE_JOINABLE (por defecto)
● PTHREAD_CREATE_DETACHED
Atributos de los hilos: SCOPE

Terminación
#include <pthread.h>
int pthread_attr_setscope( pthread_attr_t *attr,
int contentionscope);
int pthread_attr_getscope( pthread_attr_t *attr,
int *contentionscope);

Establecer si compiten por la CPU a nivel de proceso o


en todo el sistema. El argumento contentionscope:
● PTHREAD_SCOPE_PROCESS
● PTHREAD_SCOPE_SYSTEM
Atributos de los hilos: POLÍTICA DE PLANIFICACIÓN

Terminación
#include <pthread.h>
int pthread_attr_setschedpolicy( pthread_attr_t *attr,
int policy);
int pthread_attr_getschedpolicy( pthread_attr_t *attr,
int *policy);

Establecer la política de planificación del hilo. El


argumento policy puede establecerse a:
● SCHED_FIFO
● SCHED_RR
● SCHED_OTHER
Atributos de los hilos: TAMAÑO DE LA PILA

Terminación
#include <pthread.h>
int pthread_attr_setstacksize( pthread_attr_t *attr,
size_t stacksize);
int pthread_attr_getstacksize( pthread_attr_t *attr,
size_t *restrict ss);

Establecer el tamaño de la pila que hay que reservar


para el hilo en bytes.
Índice
1.1. Estándar POSIX
Capítulo 1 1.2. PThreads
Introducción

2.1. Identificación de hilos


2.2. Creación
Capítulo 2.
2.3. Bloqueo o espera a la finalización de hilos
Operaciones 2.4. Terminación
2.5. Atributos (configuración)

Capítulo 3.
3.1. Caracoles
Ejemplo
Ejemplo: Caracoles
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>

#define N_CAR 4
#define M_TOT 50

/* VARIABLES GLOBALES */
float metros[N_CAR];
int i, carrera;

/* FUNCION ALEATORIA */
long alea(long min, long max) {
return(min+1.*(max-min+1)*random()/(RAND_MAX+1.0));
} // Devuelve un long recibido como argumento
Ejemplo: Caracoles
void avance_caracol(int c) {
while (carrera) {
metros[c] += .001*alea(100,200); // Avanza entre 100 i 200 mm.
if (metros[c] >= M_TOT) {
carrera=0; // Carrera finalizada
sleep(1); // Pausa
printf("\n*** HA GANADO EL CARACOL NÚMERO %d ***\n\n",c);
}
usleep(alea(10000,30000)); // Descansa entre 10 i 30 ms.
}
}

void *func_caracoles(void *p) {


int c=*((int *)p);
printf("Comienza el caracol %d\n", c);
avance_caracol(c);
}
Ejemplo: Caracoles
/* PRINCIPAL */
int main (void) {
pthread_t caracol[N_CAR];
int j=0
srandom(time(NULL)); // Inicializa el aleatorio

for (i=0; i<N_CAR; i++) {


metros[i]=0.0;
} // En la salida

carrera=1; //Debe ser TRUE para que los caracoles avancen


for (i=0; i<N_CAR; i++) {
pthread_create(&caracol[i], NULL, func_caracoles, (void *)&i);
} // Caracoles en carrera, cada uno ejecutado por un thread

Ejemplo: Caracoles
while(carrera) {
usleep(500000); // Pausa entre resultados parciales
printf("Parcial %3d - ",++j);
for (i=0; i<N_CAR; i++) {
printf("%d =>%6.3f ",i,metros[i]);
}
printf("\n");
}

for (i=0; i<N_CAR; i++) {


pthread_join(caracol[i], NULL);
} // Bucle para esperar la finalización de los caracoles

return(0);
}
SOLUCION
/* PRINCIPAL */
int main (void) {
pthread_t caracol[N_CAR];
int j=0;
int ids[N_CAR];
srandom(time(NULL)); // Inicializa el aleatorio

for (i=0; i<N_CAR; i++) {


metros[i]=0.0;
} // En la salida

carrera=1; //Debe ser TRUE para que los caracoles avancen


for(i=0; i<N_CAR; i++) {
ids[i]=i;
pthread_create(&caracol[i], NULL, func_caracoles, (void *)&ids[i]);
} // Caracoles en carrera, cada uno ejecutado por un thread
Gracias por su atención

Antonio Molina Picó


13 de febrero de 2024

También podría gustarte