pthreads
Los hilos de POSIX, también conocidos como pthreads, son un modelo de ejecución independiente del lenguaje de programación. Este modelo permite que un programa controle varios flujos de trabajo diferentes que se solapan en el tiempo. A cada uno de estos flujos de trabajo se los conoce como subprocesos, y su creación y control se realiza mediante llamadas a la API de hilos de POSIX, definida por el estándar POSIX.1c, extensiones a los hilos (IEEE Std 1003.1c-1995).
Hay implementaciones de la API en muchos sistemas operativos compatibles con POSIX o similares a UNIX, como por ejemplo FreeBSD, NetBSD, OpenBSD, Linux, macOS, Android,[1] Solaris, Redox y AUTOSAR Adaptive. Estas implementaciones normalmente vienen en forma de librería. En Microsoft Windows también hay implementaciones, aunque no nativas: con SFU/SUA se podían utilizar los hilos de POSIX, o bien con librerías externas como pthreads-w32,[2] que implementa el funcionamiento de pthreads utilizando el API nativo de hilos de Windows.
Contenido
pthreads define un conjunto de tipos, funciones y constantes en el lenguaje de programación C. Se implementa con un encabezado pthread.h
y una biblioteca de hilos.
Existen alrededor de 100 procedimientos, todos con el prefijo pthread_
, y pueden dividirse en cuatro categorías:
- Gestión de hilos (creación, sincronización al finalizar, etc.).
- Exclusión mutua.
- Monitores.
- Sincronización entre hilos.
La API de semáforos POSIX funciona con los hilos de POSIX, pero no forma parte del estándar ya que se definió en la extensión POSIX.1b, extensiones de tiempo real (IEEE Std 1003.1b-1993). Como consecuencia de ello, los procedimientos de semáforo tienen el prefijo sem_
en lugar de pthread_
.
Ejemplo
Un ejemplo que ilustra el uso de pthreads en C:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <pthread.h>
#include <unistd.h>
#define NUM_HILOS 5
void *realiza_trabajo(void *args) {
int indice = *((int *) args);
int duerme = 1 + rand() % NUM_HILOS;
printf("Hilo %d iniciado.\n", indice);
printf("Hilo %d dormirá %d segundos.\n", indice, duerme);
sleep(duerme);
printf("Hilo %d finaliza.\n", indice);
return NULL;
}
int main(void) {
pthread_t hilos[NUM_HILOS];
int args_hilos[NUM_HILOS];
int i;
int result;
/* Crea todos los hilos, uno a uno */
for (i = 0; i < NUM_HILOS; i++) {
printf("MAIN: Creando hilo %d.\n", i);
args_hilos[i] = i;
result = pthread_create(&hilos[i], NULL, realiza_trabajo, &args_hilos[i]);
assert(!result);
}
printf("MAIN: todos los hilos creados.\n");
/* Espera a que cada hilo termine su trabajo */
for (i = 0; i < NUM_HILOS; i++) {
result = pthread_join(hilos[i], NULL);
assert(!result);
printf("MAIN: El hilo %d ha terminado.\n", i);
}
printf("MAIN termina.\n");
return 0;
}
Este programa crea cinco hilos, cada uno de los cuales ejecuta la función realiza_trabajo que imprime el identificador del hilo por salida estándar. Para compilar este programa utilizamos gcc:
gcc ejemplo_pthreads.c -lpthread -o ejemplo_pthreads
Y este es uno de las posibles salidas al ejecutar el programa:
MAIN: Creando hilo 0.
MAIN: Creando hilo 1.
Hilo 0 iniciado.
Hilo 0 dormirá 4 segundos.
Hilo 1 iniciado.
Hilo 1 dormirá 2 segundos.
MAIN: Creando hilo 2.
MAIN: Creando hilo 3.
Hilo 2 iniciado.
Hilo 2 dormirá 3 segundos.
MAIN: Creando hilo 4.
Hilo 3 iniciado.
Hilo 3 dormirá 1 segundos.
Hilo 4 iniciado.
Hilo 4 dormirá 4 segundos.
MAIN: todos los hilos creados.
Hilo 3 finaliza.
Hilo 1 finaliza.
Hilo 2 finaliza.
Hilo 0 finaliza.
Hilo 4 finaliza.
MAIN: El hilo 0 ha terminado.
MAIN: El hilo 1 ha terminado.
MAIN: El hilo 2 ha terminado.
MAIN: El hilo 3 ha terminado.
MAIN: El hilo 4 ha terminado.
MAIN termina.
Hilos de POSIX para Windows
Windows no soporta el estándar de pthreads de forma nativa. Hay proyectos de terceros, como Pthreads4w, que buscan aportar un wrapper o envoltorio de implementación. Este proyecto también se puede usar para portabilizar código desarrollado para Unix a Windows, con pocas o ninguna modificación.
El proyecto MinGW-w64 también contiene un wrapper que implementa pthreads, llamado winpthreads. Su intención es usar llamadas al sistema nativas, a diferencia del proyecto Pthreads4w.[3]
El subsistema Interix, disponible en el paquete Servicios de Windows para UNIX/SFU proporciona un puerto nativo de la API de pthreads, esto es, no utiliza la API de Win32 sino directamente la interfaz de llamadas al sistema operativo.[4]
Referencias
- ↑ «libc/bionic/pthread.c - platform/bionic - Git at Google». android.googlesource.com.
- ↑ «Pthread Win-32: Level of standards conformance». 22 de diciembre de 2006. Archivado desde el original el 11 de junio de 2010. Consultado el 29 de agosto de 2010.
- ↑ see http://locklessinc.com/articles/pthreads_on_windows which is where it was originally derived from
- ↑ «Chapter 1: Introduction to Windows Services for UNIX 3.5».
Otras lecturas
- David R. Butenhof (1997). Programming with POSIX Threads. Addison-Wesley. ISBN 978-0-201-63392-4.
- Bradford Nichols; Dick Buttlar; Jacqueline Proulx Farell (September 1996). Pthreads Programming. O'Reilly & Associates. ISBN 978-1-56592-115-3.
- Charles J. Northrup (25 de enero de 1996). Programming with UNIX Threads. John Wiley & Sons. ISBN 978-0-471-13751-1.
- Kay A. Robbins; Steven Robbins (2003). UNIX Systems Programming. Prentice-Hall. ISBN 978-0-13-042411-2.