Taller de pthreads
Javier Pimas
DC - FCEyN - UBA
Sistemas Operativos (taller), 2do cuatrimestre de 2010.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Introduccion a pthreads
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Uso basico de la biblioteca
Primeros pasos con pthreads
Sincronizacion elemental
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Repaso: Que son los threads?
V/F?
Son como procesos light.
as estado que un thread.
V En general un proceso involucra m
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Repaso: Que son los threads?
V/F?
Son como procesos light.
as estado que un thread.
V En general un proceso involucra m
V/F?
Son como mini-procesos dentro de un proceso.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Repaso: Que son los threads?
V/F?
Son como procesos light.
as estado que un thread.
V En general un proceso involucra m
V/F?
Son como mini-procesos dentro de un proceso.
V Todo thread vive en (l
ease: es parte de) un proceso particular.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Introduccion a pthreads
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Uso basico de la biblioteca
Primeros pasos con pthreads
Sincronizacion elemental
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Breve paneo por la realidad
Rapidito y sin dolor (ni mucho detalle): qu
e tipos de threads hay actualmente
ah afuera, de d
onde vienen y para d
onde parecen estar rumbeando.
Threads Java.
Threads Windows.
Threads del siglo XX.
Threads del siglo XXI pthreads.
Tendencias, industria, futuro.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Siglo XXI: Portability con P de POSIX.
En 1995, la IE3 logr
o incorporar los threads al standard.
Versi
on vigente: IEEE POSIX 1003.1c (2004) + algo de hermen
eutica (era inevitable).
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Siglo XXI: Portability con P de POSIX.
En 1995, la IE3 logr
o incorporar los threads al standard.
Versi
on vigente: IEEE POSIX 1003.1c (2004) + algo de hermen
eutica (era inevitable).
pthreads fue un paso crucial hacia la inter-compatibilidad.
GNU/Linux, Free/Open/NetBSD, Mac OS X, AIX, HP-UX, Solaris, IRIX, Cygwin, Symbian OS . . .
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Siglo XXI: Portability con P de POSIX.
En 1995, la IE3 logr
o incorporar los threads al standard.
Versi
on vigente: IEEE POSIX 1003.1c (2004) + algo de hermen
eutica (era inevitable).
pthreads fue un paso crucial hacia la inter-compatibilidad.
GNU/Linux, Free/Open/NetBSD, Mac OS X, AIX, HP-UX, Solaris, IRIX, Cygwin, Symbian OS . . .
pthreads no es una implementaci
on sino una especificacion.
Impone API com
un y sem
antica [casi] clara. Implementaciones varias, pero [casi] intercambiables.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Siglo XXI: Portability con P de POSIX.
En 1995, la IE3 logr
o incorporar los threads al standard.
Versi
on vigente: IEEE POSIX 1003.1c (2004) + algo de hermen
eutica (era inevitable).
pthreads fue un paso crucial hacia la inter-compatibilidad.
GNU/Linux, Free/Open/NetBSD, Mac OS X, AIX, HP-UX, Solaris, IRIX, Cygwin, Symbian OS . . .
pthreads no es una implementaci
on sino una especificacion.
Impone API com
un y sem
antica [casi] clara. Implementaciones varias, pero [casi] intercambiables.
En 2003, NPTL se afianz
o como la implementacion para Linux.
Native POSIX Threads Library (donde native implica con soporte a nivel del kernel).
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Siglo XXI: Portability con P de POSIX.
En 1995, la IE3 logr
o incorporar los threads al standard.
Versi
on vigente: IEEE POSIX 1003.1c (2004) + algo de hermen
eutica (era inevitable).
pthreads fue un paso crucial hacia la inter-compatibilidad.
GNU/Linux, Free/Open/NetBSD, Mac OS X, AIX, HP-UX, Solaris, IRIX, Cygwin, Symbian OS . . .
pthreads no es una implementaci
on sino una especificacion.
Impone API com
un y sem
antica [casi] clara. Implementaciones varias, pero [casi] intercambiables.
En 2003, NPTL se afianz
o como la implementacion para Linux.
Native POSIX Threads Library (donde native implica con soporte a nivel del kernel).
El uso de threads se volvi
o aceptable para muchos mas proyectos.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Referencias
IEEE Online Standards: POSIX
http://standards.ieee.org/catalog/olis/arch_posix.html
http://www.unix.org/version3/ieee_std.html
Tutorial del LLNL sobre pthreads
https://computing.llnl.gov/tutorials/pthreads/
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Como se define thread en el standard?
En la secci
on Base Definitions del IEEE 1003.1c leemos:
Thread (3.393) A single flow of control within a process.
Each thread has its own thread ID, scheduling priority and
policy, errno value, thread-specific key/value bindings, and
the required system resources to support a flow of control.
Anything whose address may be determined by a thread,
including but not limited to static variables, storage obtained
via malloc(), directly addressable storage obtained through
implementation-defined functions, and automatic variables,
are accessible to all threads in the same process.
Thread ID (3.394) Each thread in a process is uniquely identified during its
lifetime by a value of type pthread t called a thread ID.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Introduccion a pthreads
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Uso basico de la biblioteca
Primeros pasos con pthreads
Sincronizacion elemental
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Lo mo, lo tuyo, lo propio, lo ajeno.
C
omo describir el modelo de acceso a memoria que muestra el diagrama?
Compartida? Privada? Distribuida? Un hbrido . . . ?
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Lo mo, lo tuyo, lo propio, lo ajeno.
C
omo describir el modelo de acceso a memoria que muestra el diagrama?
Compartida? Privada? Distribuida? Un hbrido . . . ?
Cu
antos threads hay ah?
Procesos? M
aquinas?
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Lo mo, lo tuyo, lo propio, lo ajeno.
C
omo describir el modelo de acceso a memoria que muestra el diagrama?
Compartida? Privada? Distribuida? Un hbrido . . . ?
Cu
antos threads hay ah?
Procesos? M
aquinas?
No puede ser distribuida.
Algo de compartida hay.
Algo de privada tambi
en.
Qu
e predomina?
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Por que threads y no procesos?
Por razones de eficiencia/performance
fork() es considerablemente m
as caro que pthread create().
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Por que threads y no procesos?
Por razones de eficiencia/performance
fork() es considerablemente m
as caro que pthread create().
El context-switching tambien es m
as pesado y costoso entre procesos.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Por que threads y no procesos?
Por razones de eficiencia/performance
fork() es considerablemente m
as caro que pthread create().
El context-switching tambien es m
as pesado y costoso entre procesos.
El overhead total usualmente vara en 1 orden de magnitud.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Por que threads y no procesos?
Por razones de eficiencia/performance
fork() es considerablemente m
as caro que pthread create().
El context-switching tambien es m
as pesado y costoso entre procesos.
El overhead total usualmente vara en 1 orden de magnitud.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Por que threads y no procesos?
Por razones de eficiencia/performance
fork() es considerablemente m
as caro que pthread create().
El context-switching tambien es m
as pesado y costoso entre procesos.
El overhead total usualmente vara en 1 orden de magnitud.
Demo: time forks vs. time pthreads
...
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Por que podra querer procesos y no threads?
Un ejemplo: cuando la promiscuidad amenaza la seguridad
Ejemplo: algo peque
no pero muy sensible, tipo ssh-agent .
Otro similar: cuando va en detrimento de la confiabilidad
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Por que podra querer procesos y no threads?
Un ejemplo: cuando la promiscuidad amenaza la seguridad
Ejemplo: algo peque
no pero muy sensible, tipo ssh-agent .
Idea: usando threads, compartir 1 tal proceso entre N usuarios.
Otro similar: cuando va en detrimento de la confiabilidad
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Por que podra querer procesos y no threads?
Un ejemplo: cuando la promiscuidad amenaza la seguridad
Ejemplo: algo peque
no pero muy sensible, tipo ssh-agent .
Idea: usando threads, compartir 1 tal proceso entre N usuarios.
Ni a palos! Esa memoria es ma, ma, ma!
Otro similar: cuando va en detrimento de la confiabilidad
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Por que podra querer procesos y no threads?
Un ejemplo: cuando la promiscuidad amenaza la seguridad
Ejemplo: algo peque
no pero muy sensible, tipo ssh-agent .
Idea: usando threads, compartir 1 tal proceso entre N usuarios.
Ni a palos! Esa memoria es ma, ma, ma!
Otro similar: cuando va en detrimento de la confiabilidad
Ejemplo: tengo una 2da instancia de cierto daemon crtico.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Por que podra querer procesos y no threads?
Un ejemplo: cuando la promiscuidad amenaza la seguridad
Ejemplo: algo peque
no pero muy sensible, tipo ssh-agent .
Idea: usando threads, compartir 1 tal proceso entre N usuarios.
Ni a palos! Esa memoria es ma, ma, ma!
Otro similar: cuando va en detrimento de la confiabilidad
Ejemplo: tengo una 2da instancia de cierto daemon crtico.
Idea: configurarlo como un segundo thread del mismo proceso.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Por que podra querer procesos y no threads?
Un ejemplo: cuando la promiscuidad amenaza la seguridad
Ejemplo: algo peque
no pero muy sensible, tipo ssh-agent .
Idea: usando threads, compartir 1 tal proceso entre N usuarios.
Ni a palos! Esa memoria es ma, ma, ma!
Otro similar: cuando va en detrimento de la confiabilidad
Ejemplo: tengo una 2da instancia de cierto daemon crtico.
Idea: configurarlo como un segundo thread del mismo proceso.
Ni loco! Quiero un proceso aparte. Idealmente, en otro equipo.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Por que podra querer procesos y no threads?
Un ejemplo: cuando la promiscuidad amenaza la seguridad
Ejemplo: algo peque
no pero muy sensible, tipo ssh-agent .
Idea: usando threads, compartir 1 tal proceso entre N usuarios.
Ni a palos! Esa memoria es ma, ma, ma!
Otro similar: cuando va en detrimento de la confiabilidad
Ejemplo: tengo una 2da instancia de cierto daemon crtico.
Idea: configurarlo como un segundo thread del mismo proceso.
Ni loco! Quiero un proceso aparte. Idealmente, en otro equipo.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Por que podra querer procesos y no threads?
Un ejemplo: cuando la promiscuidad amenaza la seguridad
Ejemplo: algo peque
no pero muy sensible, tipo ssh-agent .
Idea: usando threads, compartir 1 tal proceso entre N usuarios.
Ni a palos! Esa memoria es ma, ma, ma!
Otro similar: cuando va en detrimento de la confiabilidad
Ejemplo: tengo una 2da instancia de cierto daemon crtico.
Idea: configurarlo como un segundo thread del mismo proceso.
Ni loco! Quiero un proceso aparte. Idealmente, en otro equipo.
Hay muchos m
as ejemplos (ejercicio: pensar algunos m
as), pero sigamos adelante.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Primeros pasos con pthreads
Sincronizaci
on elemental
Introduccion a pthreads
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Uso basico de la biblioteca
Primeros pasos con pthreads
Sincronizacion elemental
Introducci
on a pthreads
Uso b
asico de la biblioteca
Primeros pasos con pthreads
Sincronizaci
on elemental
La API es grande pero el coreazon es chico.
tipo de datos (tid) pthread t
crear nuevo thread pthread create(thread, attr, startfn, arg)
terminar un thread pthread exit(status)
crear atributos pthread attr init(attr)
destruir atributos pthread attr destroy(attr)
Por concisi
on hemos omitido aqu las dem
as primitivas (unas 90) y abstraido bastante los tipos de los par
ametros
(casi todos son punteros-a-eso, etc). Para los detalles escabrosos de cada tipo y funci
on, v
ease
man 3 pthread .
Introducci
on a pthreads
Uso b
asico de la biblioteca
Primeros pasos con pthreads
Sincronizaci
on elemental
Pasando parametros y usando atributos.
crear atributos pthread attr init(attr)
crear nuevo thread pthread create(thread, attrs, startfun, arg)
Introducci
on a pthreads
Uso b
asico de la biblioteca
Primeros pasos con pthreads
Sincronizaci
on elemental
Pasando parametros y usando atributos.
crear atributos pthread attr init(attr)
crear nuevo thread pthread create(thread, attrs, startfun, arg)
attr Atributos. NULL todos los attrs en valores por defecto.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Primeros pasos con pthreads
Sincronizaci
on elemental
Pasando parametros y usando atributos.
crear atributos pthread attr init(attr)
crear nuevo thread pthread create(thread, attrs, startfun, arg)
attr Atributos. NULL todos los attrs en valores por defecto.
startfun Puntero a funci
on que recibe 1 puntero a void.
No puede ser NULL. (el thread necesita un punto de entrada!)
Introducci
on a pthreads
Uso b
asico de la biblioteca
Primeros pasos con pthreads
Sincronizaci
on elemental
Pasando parametros y usando atributos.
crear atributos pthread attr init(attr)
crear nuevo thread pthread create(thread, attrs, startfun, arg)
attr Atributos. NULL todos los attrs en valores por defecto.
startfun Puntero a funci
on que recibe 1 puntero a void.
No puede ser NULL. (el thread necesita un punto de entrada!)
arg(s) Instancia de void* que recibir
a startfun(void* arg).
NULL OK, si startfun() no lo necesita . . . .
Introducci
on a pthreads
Uso b
asico de la biblioteca
Primeros pasos con pthreads
Sincronizaci
on elemental
Pasando parametros y usando atributos.
crear atributos pthread attr init(attr)
crear nuevo thread pthread create(thread, attrs, startfun, arg)
attr Atributos. NULL todos los attrs en valores por defecto.
startfun Puntero a funci
on que recibe 1 puntero a void.
No puede ser NULL. (el thread necesita un punto de entrada!)
arg(s) Instancia de void* que recibir
a startfun(void* arg).
NULL OK, si startfun() no lo necesita . . . .
Para pasar estructuras mas complejas
1
definimos una struct con campos a gusto
al crear un thread, le pasamos un puntero-a-eso
el nuevo thread recibe ese puntero y . . . lo castea a lo macho.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Primeros pasos con pthreads
Sincronizaci
on elemental
Compilando codigo que usa pthreads
Facil; basta con . . .
CFLAGS=-pthread
(agregar al Makefile)
gcc -pthread -o test test.c
g++ -pthread -o test test.cpp
Eso agrega los -I necesarios para compilar, los -L para linkear la biblioteca, etc.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Primeros pasos con pthreads
Sincronizaci
on elemental
Introduccion a pthreads
Procesos y threads (repaso)
El mundo real: presente, pasado y futuro
Modelo de memoria de pthreads
Uso basico de la biblioteca
Primeros pasos con pthreads
Sincronizacion elemental
Introducci
on a pthreads
Uso b
asico de la biblioteca
Primeros pasos con pthreads
Sincronizaci
on elemental
API basica para exclusion mutua.
tipo de datos pthread mutex t
crear mutex pthread mutex init(mutex, attr)
destruir mutex pthread mutex destroy(mutex)
espera bloqueante pthread mutex lock(mutex)
intento no bloqueante pthread mutex trylock(mutex)
liberaci
on (signal) pthread mutex unlock(mutex)
Introducci
on a pthreads
Uso b
asico de la biblioteca
Primeros pasos con pthreads
Sincronizaci
on elemental
API basica para variables de condicion.
tipo de datos pthread cond t
crear VC pthread cond init(cond, attr)
destruir VC pthread cond destroy(mutex)
crear atributos pthread condattr init(attr)
destruir atributos pthread condattr destroy(mutex)
wait pthread cond wait(cond, mutex)
signal pthread cond signal(cond)
broadcast pthread cond broadcast(cond)
Introducci
on a pthreads
Uso b
asico de la biblioteca
Primeros pasos con pthreads
Sincronizaci
on elemental
Modo de uso de VCs y mutexes.
Notar que una VC siempre se usa con un mutex asociado.
Hay reglas de juego ah (usar o no el mismo mutex ac
a o all
a, etc).
Es responsabilidad del programador conocer y respetar estos contratos.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Primeros pasos con pthreads
Sincronizaci
on elemental
Modo de uso de VCs y mutexes.
Notar que una VC siempre se usa con un mutex asociado.
Hay reglas de juego ah (usar o no el mismo mutex ac
a o all
a, etc).
Es responsabilidad del programador conocer y respetar estos contratos.
Cuando un thread que debe tener el mutex ya tomado
llama a wait() , suelta el mutex y entra en espera bloqueante.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Primeros pasos con pthreads
Sincronizaci
on elemental
Modo de uso de VCs y mutexes.
Notar que una VC siempre se usa con un mutex asociado.
Hay reglas de juego ah (usar o no el mismo mutex ac
a o all
a, etc).
Es responsabilidad del programador conocer y respetar estos contratos.
Cuando un thread que debe tener el mutex ya tomado
llama a wait() , suelta el mutex y entra en espera bloqueante.
Cuando un thread llama a signal() , otro thread en espera, de
haberlo, se despierta de su wait() con el mutex ya adquirido.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Primeros pasos con pthreads
Sincronizaci
on elemental
Modo de uso de VCs y mutexes.
Notar que una VC siempre se usa con un mutex asociado.
Hay reglas de juego ah (usar o no el mismo mutex ac
a o all
a, etc).
Es responsabilidad del programador conocer y respetar estos contratos.
Cuando un thread que debe tener el mutex ya tomado
llama a wait() , suelta el mutex y entra en espera bloqueante.
Cuando un thread llama a signal() , otro thread en espera, de
haberlo, se despierta de su wait() con el mutex ya adquirido.
Si no hay ning
un thread esperando a esa VC, tanto los signal()
como los broadcast() se ignoran: no tienen efecto ni se acumulan.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Primeros pasos con pthreads
Sincronizaci
on elemental
Modo de uso de VCs y mutexes (cont.)
Sea count una variable global que lleva la cuenta de algo. Interesa que sea
incrementada ante cierto evento, detectable por alguno de N threads activos;
lease, uno cualquiera de ellos en cada ocurrencia del evento en cuesti
on.
Introducci
on a pthreads
Uso b
asico de la biblioteca
Primeros pasos con pthreads
Sincronizaci
on elemental
Modo de uso de VCs y mutexes (cont.)
Sea count una variable global que lleva la cuenta de algo. Interesa que sea
incrementada ante cierto evento, detectable por alguno de N threads activos;
lease, uno cualquiera de ellos en cada ocurrencia del evento en cuesti
on.
varcond.c
pthread_mutex_lock(&count_mutex);
if(count < COUNT_LIMIT) {
pthread_cond_wait(&count_threshold_cv, &count_mutex);
printf("count(): thread %ld: cond. signal received.\n", my_id);
count += 125;
printf("count(): thread %ld: count is now %d.\n", my_id, count);
}
pthread_mutex_unlock(&count_mutex);
pthread_exit(NULL);