concurrencia en c++ moderno - wordpress.comconcurrencia en c++ moderno aviso esta obra está bajo...

67
Concurrencia en C++ moderno Concurrencia en C++ moderno codemotion 2014 J. Daniel Garcia Grupo ARCOS Universidad Carlos III de Madrid 21 de noviembre de 2014 cbed J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 1/52

Upload: others

Post on 25-Feb-2020

12 views

Category:

Documents


0 download

TRANSCRIPT

Concurrencia en C++ moderno

Concurrencia en C++ modernocodemotion 2014

J. Daniel Garcia

Grupo ARCOSUniversidad Carlos III de Madrid

21 de noviembre de 2014

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 1/52

Concurrencia en C++ moderno

Aviso

c Esta obra está bajo una Licencia Creative CommonsAtribución-NoComercial-SinDerivar 4.0 Internacional.

b Debes dar crédito en la obra en la forma especificadapor el autor o licenciante.

e El licenciante permite copiar, distribuir y comunicar pú-blicamente la obra. A cambio, esta obra no puede serutilizada con fines comerciales — a menos que se ob-tenga el permiso expreso del licenciante.

d El licenciante permite copiar, distribuir, transmitir y co-municar públicamente solamente copias inalteradas dela obra – no obras derivadas basadas en ella.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 2/52

Concurrencia en C++ moderno

ARCOS@uc3m

UC3M: Una universidad joven, internacional y orientada ala investigación.ARCOS: Un grupo de investigación aplicada.

Líneas: Computación de altas prestaciones, Big data,Sistemas Ciberfísicos, y Modelos de programación para lamejora de las aplicaciones

Mejorando las aplicaciones:REPARA: Reengineering and Enabling Performance andpoweR of Applications.RePhrase: REfactoring Parallel Heterogeneous ResourceAware Applications.

Normalización:ISO/IEC JTC/SC22/WG21.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 3/52

Concurrencia en C++ moderno

La concurrencia está aquí

1 La concurrencia está aquí

2 Concurrencia mínima

3 Hilos

4 Exclusión mutua

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 4/52

Concurrencia en C++ moderno

La concurrencia está aquí

The free lunch is over

1 La concurrencia está aquíThe free lunch is overC++ y la concurrencia

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 5/52

Concurrencia en C++ moderno

La concurrencia está aquí

The free lunch is over

Evolución

Hasta 2005 (aprox.) incremento sostenido en frecuenciasde reloj.

Incrementos del rendmiento en torno al 52 % anual.

Pero entonces . . .Se acabó la fiesta (The free lunch is over).Estabilización de frecuencias de reloj en torno a 3GHz.La industria apuesta por multi/many-core.

La concurrencia y el paralelismo se convierten en másrelevantes.

Recuerda: No son lo mismo pero muy interrelacionados.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 6/52

Concurrencia en C++ moderno

La concurrencia está aquí

The free lunch is over

Evolución

Hasta 2005 (aprox.) incremento sostenido en frecuenciasde reloj.

Incrementos del rendmiento en torno al 52 % anual.

Pero entonces . . .Se acabó la fiesta (The free lunch is over).Estabilización de frecuencias de reloj en torno a 3GHz.La industria apuesta por multi/many-core.

La concurrencia y el paralelismo se convierten en másrelevantes.

Recuerda: No son lo mismo pero muy interrelacionados.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 6/52

Concurrencia en C++ moderno

La concurrencia está aquí

The free lunch is over

Evolución

Hasta 2005 (aprox.) incremento sostenido en frecuenciasde reloj.

Incrementos del rendmiento en torno al 52 % anual.

Pero entonces . . .Se acabó la fiesta (The free lunch is over).Estabilización de frecuencias de reloj en torno a 3GHz.La industria apuesta por multi/many-core.

La concurrencia y el paralelismo se convierten en másrelevantes.

Recuerda: No son lo mismo pero muy interrelacionados.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 6/52

Concurrencia en C++ moderno

La concurrencia está aquí

The free lunch is over

Concurrencia y paralelismo

Concurrencia: Ejecución de varias tareas de forma que elinicio de una se encuentra entre el principio y final de otra.

Puede darse en un único procesador.Objetivos:

Mejorar aprovechamiento de recursos (trabajos por unidadde tiempo).Mejorar experiencia de respuesta en presencia de E/S.Mejorar estructura de programas basados en tareas.

Paralelismo: Ejecución de varias tareas de formasimultánea.

Típicamente cada tarea usa un procesador (o un core).Objetivos:

Mejorar el rendimiento (tiempo de un trabajo).Mejorar la escalabilidad.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 7/52

Concurrencia en C++ moderno

La concurrencia está aquí

The free lunch is over

Concurrencia y paralelismo

Concurrencia: Ejecución de varias tareas de forma que elinicio de una se encuentra entre el principio y final de otra.

Puede darse en un único procesador.Objetivos:

Mejorar aprovechamiento de recursos (trabajos por unidadde tiempo).Mejorar experiencia de respuesta en presencia de E/S.Mejorar estructura de programas basados en tareas.

Paralelismo: Ejecución de varias tareas de formasimultánea.

Típicamente cada tarea usa un procesador (o un core).Objetivos:

Mejorar el rendimiento (tiempo de un trabajo).Mejorar la escalabilidad.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 7/52

Concurrencia en C++ moderno

La concurrencia está aquí

C++ y la concurrencia

1 La concurrencia está aquíThe free lunch is overC++ y la concurrencia

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 8/52

Concurrencia en C++ moderno

La concurrencia está aquí

C++ y la concurrencia

¿Por qué?

Portabilidad:Antes de 2011 diversos modelos de programaciónconcurrente.

Windows Threads, POSIX Threads, . . .Extensiones en el compilador: __declspec( thread ),__thread, . . .

Necesidad de código no portable para operaciones libresde cerrojos.

Típicamente en ensamblador.

Completitud y corrección:Un modelo de hilos no puede implementarse sin soportedel compilador.

H. Bohem. Threads cannot be implemented as a library.PLDI’2005.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 9/52

Concurrencia en C++ moderno

La concurrencia está aquí

C++ y la concurrencia

¿Por qué?

Portabilidad:Antes de 2011 diversos modelos de programaciónconcurrente.

Windows Threads, POSIX Threads, . . .Extensiones en el compilador: __declspec( thread ),__thread, . . .

Necesidad de código no portable para operaciones libresde cerrojos.

Típicamente en ensamblador.

Completitud y corrección:Un modelo de hilos no puede implementarse sin soportedel compilador.

H. Bohem. Threads cannot be implemented as a library.PLDI’2005.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 9/52

Concurrencia en C++ moderno

La concurrencia está aquí

C++ y la concurrencia

¿Por qué?

Portabilidad:Antes de 2011 diversos modelos de programaciónconcurrente.

Windows Threads, POSIX Threads, . . .Extensiones en el compilador: __declspec( thread ),__thread, . . .

Necesidad de código no portable para operaciones libresde cerrojos.

Típicamente en ensamblador.

Completitud y corrección:Un modelo de hilos no puede implementarse sin soportedel compilador.

H. Bohem. Threads cannot be implemented as a library.PLDI’2005.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 9/52

Concurrencia en C++ moderno

La concurrencia está aquí

C++ y la concurrencia

Y además . . .

Formalización del modelo de memoria.Hasta 2005 varios fabricantes no habían clarificado sumodelo de consistencia de memoria.Formalización compleja.Problemas de implementación en lenguajes (Java, C, C++).Efecto: Clarificación de los fabricantes de procesadores.

Efecto sobre C11.Incluisión de un modelo de hilos muy similar.Portabilidad de hilos en C.

Mejor que PThreads!

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 10/52

Concurrencia en C++ moderno

La concurrencia está aquí

C++ y la concurrencia

Y además . . .

Formalización del modelo de memoria.Hasta 2005 varios fabricantes no habían clarificado sumodelo de consistencia de memoria.Formalización compleja.Problemas de implementación en lenguajes (Java, C, C++).Efecto: Clarificación de los fabricantes de procesadores.

Efecto sobre C11.Incluisión de un modelo de hilos muy similar.Portabilidad de hilos en C.

Mejor que PThreads!

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 10/52

Concurrencia en C++ moderno

Concurrencia mínima

1 La concurrencia está aquí

2 Concurrencia mínima

3 Hilos

4 Exclusión mutua

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 11/52

Concurrencia en C++ moderno

Concurrencia mínima

Tareas asíncronas

2 Concurrencia mínimaTareas asíncronasParámetros y resultados de una tarea

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 12/52

Concurrencia en C++ moderno

Concurrencia mínima

Tareas asíncronas

Historia de dos tareas

tasks.h

void f () {using namespace std;constexpr int max = 10;for ( int i=0; i<max; ++i) {

this_thread :: sleep_for(chrono::milliseconds(5)) ;cout.put( ’+’ ) . flush () ;

}}

void g() {using namespace std;constexpr int max = 20;for ( int i=0; i<max; ++i) {

this_thread :: sleep_for(chrono::milliseconds(5)) ;cout.put( ’∗ ’ ) . flush () ;

}}

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 13/52

Concurrencia en C++ moderno

Concurrencia mínima

Tareas asíncronas

Ejecutando las tareas secuencialmente

main1.cpp

#include <chrono>#include <thread>#include <iostream>#include "tasks.h"

int main() {f () ;g() ;return 0;

}

$ time ./test1++++++++++********************real 0m0.158suser 0m0.004ssys 0m0.000s

Ambas tareas se pueden ejecutar concurrentemente.cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 14/52

Concurrencia en C++ moderno

Concurrencia mínima

Tareas asíncronas

Ejecutando las tareas concurrentemente

main2.cpp

#include <chrono>#include <thread>#include <future>#include <iostream>#include "tasks.h"

int main() {using namespace std;

auto r1 = async(launch::async, f) ;auto r2 = async(launch::async, g);

r1.get() ;r2.get() ;

return 0;}

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 15/52

Concurrencia en C++ moderno

Concurrencia mínima

Tareas asíncronas

Concurrencia

$ time ./test1+*+**+*+*+*+*+*+*+*+**********real 0m0.106suser 0m0.004ssys 0m0.000s

Salida entrelazada a cout.Aprovechamiento del tiempo.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 16/52

Concurrencia en C++ moderno

Concurrencia mínima

Tareas asíncronas

Políticas de ejecución

La biblioteca ofrece dos políticas de ejecución.std::launch::async. Ejecución asíncrona posiblemente(as-if) en otro hilo.std::launch::deferred. Ejecución en el mismo hilo cuandose invoca a get.

¿Y si no se especifica la política?

std :: async(f) ;

Como si se invocase a std::launch::async |std::launch::deferred.La implementación decide.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 17/52

Concurrencia en C++ moderno

Concurrencia mínima

Tareas asíncronas

Políticas de ejecución

La biblioteca ofrece dos políticas de ejecución.std::launch::async. Ejecución asíncrona posiblemente(as-if) en otro hilo.std::launch::deferred. Ejecución en el mismo hilo cuandose invoca a get.

¿Y si no se especifica la política?

std :: async(f) ;

Como si se invocase a std::launch::async |std::launch::deferred.La implementación decide.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 17/52

Concurrencia en C++ moderno

Concurrencia mínima

Parámetros y resultados de una tarea

2 Concurrencia mínimaTareas asíncronasParámetros y resultados de una tarea

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 18/52

Concurrencia en C++ moderno

Concurrencia mínima

Parámetros y resultados de una tarea

Una tarea de cálculo: main3.cpp (I)

#include <chrono>#include <thread>#include <future>#include <random>#include <iostream>

double f(int s, int n) {using namespace std;

default_random_engine engine(s);normal_distribution<double> gen(1.0, 0.25);

double r = 0.0;for ( int i=0; i<n; ++i) {

r += gen(engine);}

return r /n;}

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 19/52

Concurrencia en C++ moderno

Concurrencia mínima

Parámetros y resultados de una tarea

Pasando parámetros y recogiendo resultados

main3.cpp (y II)

int main() {using namespace std;

auto r1 = async(launch::async,f, 3, 1000000);auto r2 = async(launch::async,f, 115, 2500000);

cout << r1.get() << endl;cout << r2.get() << endl;

return 0;}

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 20/52

Concurrencia en C++ moderno

Concurrencia mínima

Parámetros y resultados de una tarea

Una tarea excepcional

main4.cpp (I)

#include <chrono>#include <thread>#include <future>#include <random>#include <iostream>

class mi_error {};

double f(int n) {if (n==0) throw mi_error{};else return 1000.0/n;

}

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 21/52

Concurrencia en C++ moderno

Concurrencia mínima

Parámetros y resultados de una tarea

Una tarea excepcional

main4.cpp (y III)

int main() {using namespace std;

auto r1 = async(launch::async,f, 0);

try {cout << r1.get() << endl;

}catch (const mi_error &) {

cerr << "Error" << endl;}

return 0;}

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 22/52

Concurrencia en C++ moderno

Hilos

1 La concurrencia está aquí

2 Concurrencia mínima

3 Hilos

4 Exclusión mutua

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 23/52

Concurrencia en C++ moderno

Hilos

Introducción

3 HilosIntroducciónConstrucción e identidadTerminación de hilos

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 24/52

Concurrencia en C++ moderno

Hilos

Introducción

La clase thread

La abstracción de hilo representada mediante clasestd::thread.Todos los hilos de una aplicación se ejecutan en el mismoespacio de direcciones.Cada hilo tiene su propia pila.

thread representa un enlace a un hilo del sistema.No se pueden copiar.Si se pueden mover.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 25/52

Concurrencia en C++ moderno

Hilos

Introducción

La clase thread

La abstracción de hilo representada mediante clasestd::thread.Todos los hilos de una aplicación se ejecutan en el mismoespacio de direcciones.Cada hilo tiene su propia pila.thread representa un enlace a un hilo del sistema.

No se pueden copiar.Si se pueden mover.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 25/52

Concurrencia en C++ moderno

Hilos

Introducción

Lanzamiento de hilos

Un hilo representado por la clase std::thread.Normalmente representa un hilo del SO.

void f1 () ;

struct f2 {void operator()();

};

void g() {thread t1{f1 }; // Lanza un hilo que ejecuta f1 ()thread t2{f2 () }; // Lanza un hilo que ejecuta f2 :: operator() ()

t1 . join () ; // Espera a que t1 termine.t2 . join () ; // Espera a que t2 termine.

}

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 26/52

Concurrencia en C++ moderno

Hilos

Introducción

Objetos compartidos

Dos hilos pueden acceder a un objeto compartido.Posibilidad de carreras de datos.

Acceso a datos

#include <iostream>#include <thread>

int x = 42;

void f () { ++x; }void g() { x=0; }

Ejecución de hilos

void carrera() {using namespace std;thread t1{ f };thread t2{g};

t1 . join () ;t2 . join () ;

}

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 27/52

Concurrencia en C++ moderno

Hilos

Introducción

Un poco de ayuda

$ valgrind --tool=helgrind ./carrera==21180== Helgrind, a thread error detector==21180== Copyright (C) 2007-2011, and GNU GPL’d, by OpenWorks

LLP et al.[...]==21180== Possible data race during read of size 8 at 0x5C27060

by thread #1[...]==21180== This conflicts with a previous write of size 8 by

thread #3[...]==21180== Possible data race during write of size 8 at 0x5C27050

by thread #1[...]==21180== This conflicts with a previous read of size 8 by

thread #3[...]

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 28/52

Concurrencia en C++ moderno

Hilos

Introducción

Paso de argumentos

params.cpp

#include <thread>

void f1( int x) ;

struct f2 {void operator()();f2( int px) : x{px} {}int x;

};

params.cpp

void g() {using namespace std;thread t1{f1 , 10}; // Ejecuta f1(10)thread t2{f2 {20}}; // Ejecuta f2 {20}.operator() ()thread t3 {[] { f1(42); } }; // Ejecuta una lambda

t1 . join () ;t2 . join () ;t3 . join () ;

}

Paso de parámetros simplificado sin necesidad de casts.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 29/52

Concurrencia en C++ moderno

Hilos

Introducción

Paso de argumentos

params.cpp

#include <thread>

void f1( int x) ;

struct f2 {void operator()();f2( int px) : x{px} {}int x;

};

params.cpp

void g() {using namespace std;thread t1{f1 , 10}; // Ejecuta f1(10)thread t2{f2 {20}}; // Ejecuta f2 {20}.operator() ()thread t3 {[] { f1(42); } }; // Ejecuta una lambda

t1 . join () ;t2 . join () ;t3 . join () ;

}

Paso de parámetros simplificado sin necesidad de casts.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 29/52

Concurrencia en C++ moderno

Hilos

Construcción e identidad

3 HilosIntroducciónConstrucción e identidadTerminación de hilos

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 30/52

Concurrencia en C++ moderno

Hilos

Construcción e identidad

Construcción de hilos

Un hilo se construye con una función y los argumentosque se debe pasar a la función.

Plantilla con número variable de argumentos.Seguro en tipos.

Ejemplo

void f () ;void g(int , double);

thread t1{ f }; // OKthread t2{ f , 1}; // Error: demasiados argumentos.

thread t3{g, 1, 0.5}; // OKthread t4{g}; // Error: faltan argumentos.thread t5{g, 1, "Hola"}; // Error: tipos incorrectos

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 31/52

Concurrencia en C++ moderno

Hilos

Construcción e identidad

Construcción y referencias

El constructor de thread es una plantilla con argumentosvariables.template <class F, class ...Args>explicit thread(F&& f, Args&&... args);

El paso de parámetros a un hilo es por valor.Para forzar el paso de parámetros por referencia:

Usar una función de ayuda para reference_wrapper.Usar lambdas y capturas por referencia.

void f ( registro & r) ;

void g(registro & s) {thread t1{ f ,s };thread t2{ f , ref (s) };thread t3 {[&] { f (s) ; }};

}

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 32/52

Concurrencia en C++ moderno

Hilos

Construcción e identidad

Construcción y referencias

El constructor de thread es una plantilla con argumentosvariables.template <class F, class ...Args>explicit thread(F&& f, Args&&... args);

El paso de parámetros a un hilo es por valor.Para forzar el paso de parámetros por referencia:

Usar una función de ayuda para reference_wrapper.Usar lambdas y capturas por referencia.

void f ( registro & r) ;

void g(registro & s) {thread t1{ f ,s };thread t2{ f , ref (s) };thread t3 {[&] { f (s) ; }};

}

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 32/52

Concurrencia en C++ moderno

Hilos

Construcción e identidad

Construcción en dos etapas

La construcción incluye el inicio de la ejecución del hilo.No hay operación separada para iniciar la ejecución.

Productor/Consumidor

struct productor {productor(cola<peticiones> & c);void operator()();// ...

};

struct consumidor {consumidor(cola<peticiones> & c);void operator()();// ...

};

Etapas de construcción

cola<peticiones> c;productor prod{c};consumidor cons{c};

thread tp{prod};thread tc {cons};

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 33/52

Concurrencia en C++ moderno

Hilos

Terminación de hilos

3 HilosIntroducciónConstrucción e identidadTerminación de hilos

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 34/52

Concurrencia en C++ moderno

Hilos

Terminación de hilos

Unión de tareas

Cuando un hilo desea esperar a que otro hilo finalicepuede usar la operación join().

t.join() → espera a que t haya finalizado.

hilos/join1.cpp

void f ( int i ) ;

void g() {std :: vector<std :: thread> vt;for ( int i=0; i< 8; ++i) {

vt .push_back(std::thread(f, i ) ) ;}

for (auto & t : vt ) { // Espera a que todos los hilos terminent . join () ;

}}

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 35/52

Concurrencia en C++ moderno

Hilos

Terminación de hilos

Ejemplo

progreso.cpp

void actualiza_barra() {while (! tarea_terminada()) {

this_thread :: sleep_for(chrono::second(1))actualiza_progreso();

}}

void f () {thread t {actualiza_barra};alguna_otra_cosa();t . join () ;

}

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 36/52

Concurrencia en C++ moderno

Hilos

Terminación de hilos

¿Qué pasa si se olvida join?

Si se sale del alcance donde se define el hilo, se invoca aldestructor.Problema: Se podría perder el vínculo con un hilo delsistema que se seguiría ejecutando y al que no se podríaacceder.

Si no se ha hecho join() el destructor llama a terminate().void actualiza () {

for (;;) {muestra_reloj(stead_clock::now());this_thread :: sleep_for(second{1});

}}

void f () {thread t (actualiza) ;

}

Se ejecuta terminate() al abandonar f().cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 37/52

Concurrencia en C++ moderno

Hilos

Terminación de hilos

Problemas con la destrucción

void ejemplo() {thread t1{ f }; // Hilo que ejecuta la tarea fthread t2 ; // Hilo vacío.

if (modo == modo1) {thread tg {g};// ...t2 = move(tg); // tg vacía, t2 asociada a g()

}

vector<int> v{10000}; // Podría lanzar excepcionest1 . join () ;t2 . join () ;

}

¿Qué ocurre si el constructor de v lanza una excepción.¿Qué ocurre si se llega al final con modo==modo1?

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 38/52

Concurrencia en C++ moderno

Hilos

Terminación de hilos

Hilo automático

Patrón RAII

struct hilo_automatico : thread {using thread::thread;~hilo_automatico() {

if ( t . joinable () ) t . join () ;}

};

Simplificación de código

void ejemplo() {hilo_automatico t1{ f }; // Hilo f ()hilo_automatico t2; // Hilo vacío.

if (modo == modo1) {hilo_automatico tg {g};// ...// tg vacía, t2 asociada a g()t2 = move(tg);

}

// Podría lanzar excepcionesvector<int> v{10000};

}

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 39/52

Concurrencia en C++ moderno

Hilos

Terminación de hilos

Hilo automático

Patrón RAII

struct hilo_automatico : thread {using thread::thread;~hilo_automatico() {

if ( t . joinable () ) t . join () ;}

};

Simplificación de código

void ejemplo() {hilo_automatico t1{ f }; // Hilo f ()hilo_automatico t2; // Hilo vacío.

if (modo == modo1) {hilo_automatico tg {g};// ...// tg vacía, t2 asociada a g()t2 = move(tg);

}

// Podría lanzar excepcionesvector<int> v{10000};

}

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 39/52

Concurrencia en C++ moderno

Hilos

Terminación de hilos

Hilos no asociados

Se puede usar detach() para indicar que un hilo sigaejecutando después de que el destructor se ejecute.Útil para tareas que se ejecutan como demonios.

Un demonio

void actualiza () {for (;;) {

muestra_reloj(stead_clock::now());this_thread :: sleep_for(second{1});

}}

void f () {thread t (actualiza) ;t .detach();

}

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 40/52

Concurrencia en C++ moderno

Hilos

Terminación de hilos

Problemas con hilos no asociados

Incovenientes:Se pierde el control de qué hilos están activos.No se sabe si se puede usar el resultado generado por unhilo.No se sabe si un hilo ha liberado sus recursos.Se podría acabar accediendo a objetos que han sidodestruidos.

Recomendaciones:Evitar el uso de hilos no asociados.Mover los hilos a otro alcance (via valor de retorno).Mover los hilos a un contenedor en un alcance mayor.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 41/52

Concurrencia en C++ moderno

Hilos

Terminación de hilos

Problemas con hilos no asociados

Incovenientes:Se pierde el control de qué hilos están activos.No se sabe si se puede usar el resultado generado por unhilo.No se sabe si un hilo ha liberado sus recursos.Se podría acabar accediendo a objetos que han sidodestruidos.

Recomendaciones:Evitar el uso de hilos no asociados.Mover los hilos a otro alcance (via valor de retorno).Mover los hilos a un contenedor en un alcance mayor.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 41/52

Concurrencia en C++ moderno

Exclusión mutua

1 La concurrencia está aquí

2 Concurrencia mínima

3 Hilos

4 Exclusión mutua

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 42/52

Concurrencia en C++ moderno

Exclusión mutua

Introducción

4 Exclusión mutuaIntroducciónMecanismos de espera

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 43/52

Concurrencia en C++ moderno

Exclusión mutua

Introducción

Exclusión mutua

mutex permite controlar el acceso con exclusión mutua aun recurso.

lock(): Adquiere el cerrojo asociado.unlock(): Libera el cerrojo asociado.

Ejemplo

mutex m;int x = 0;

void f () {m.lock() ;++x;m.unlock();

}

Hilos

void g() {thread t1( f ) ;thread t2( f ) ;

t1 . join () ;t2 . join () ;

cout << x << endl;}

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 44/52

Concurrencia en C++ moderno

Exclusión mutua

Introducción

Exclusión mutua

mutex permite controlar el acceso con exclusión mutua aun recurso.

lock(): Adquiere el cerrojo asociado.unlock(): Libera el cerrojo asociado.

Ejemplo

mutex m;int x = 0;

void f () {m.lock() ;++x;m.unlock();

}

Hilos

void g() {thread t1( f ) ;thread t2( f ) ;

t1 . join () ;t2 . join () ;

cout << x << endl;}

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 44/52

Concurrencia en C++ moderno

Exclusión mutua

Introducción

Problemas con lock()/unlock()

Posibles problemas:Olvido de liberar cerrojo.Excepciones.

Solución unique_lock

mutex m;int x = 0;

void f () {unique_lock<mutex> l{m}; // Adquiere el cerrojo++x;

} // Libera el cerrojo

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 45/52

Concurrencia en C++ moderno

Exclusión mutua

Introducción

Problemas con lock()/unlock()

Posibles problemas:Olvido de liberar cerrojo.Excepciones.

Solución unique_lock

mutex m;int x = 0;

void f () {unique_lock<mutex> l{m}; // Adquiere el cerrojo++x;

} // Libera el cerrojo

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 45/52

Concurrencia en C++ moderno

Exclusión mutua

Introducción

Adquisición de múltiples mutex

La función lock() permite adquirir a la vez varios mutex.Adquiere todos o ninguno.Si alguno está bloqueado espera dejando libres todos.

mutex m1, m2, m3;void f () {

lock(m1, m2, m3);// Acceso a datos compartidos

} // Cuidado: No se liberan los cerrojos

Especialmente útil en cooperación con unique_lockvoid f () {

unique_lock<mutex> l1{m1, defer_lock}, l2{m2, defer_lock};lock( l1 , l2 ) ;// Acceso a datos compartidos

} // Ahora si se liberan los cerrojos

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 46/52

Concurrencia en C++ moderno

Exclusión mutua

Introducción

Adquisición de múltiples mutex

La función lock() permite adquirir a la vez varios mutex.Adquiere todos o ninguno.Si alguno está bloqueado espera dejando libres todos.

mutex m1, m2, m3;void f () {

lock(m1, m2, m3);// Acceso a datos compartidos

} // Cuidado: No se liberan los cerrojos

Especialmente útil en cooperación con unique_lockvoid f () {

unique_lock<mutex> l1{m1, defer_lock}, l2{m2, defer_lock};lock( l1 , l2 ) ;// Acceso a datos compartidos

} // Ahora si se liberan los cerrojos

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 46/52

Concurrencia en C++ moderno

Exclusión mutua

Mecanismos de espera

4 Exclusión mutuaIntroducciónMecanismos de espera

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 47/52

Concurrencia en C++ moderno

Exclusión mutua

Mecanismos de espera

Variables condición

Mecanismo para sincronizar hilos en acceso a recursoscompartidos.

wait(): Espera en un mutex.notify_one(): Despierta a un hilo en espera.notify_all(): Despierta a todos los hilos en espera.

Colas de peticiones

class peticion ;

queue<peticion> cola;condition_variable cv;mutex m;

void productor();void consumidor();

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 48/52

Concurrencia en C++ moderno

Exclusión mutua

Mecanismos de espera

Productor

void consumidor() {for (;;) {

unique_lock<mutex> l{m};

while (cv.wait( l ) ) ;

auto p = cola. front () ;cola.pop();l .unlock() ;

procesa(p);};

}

Efecto de wait:1 Libera el cerrojo y espera una notificación.2 Adquiere el cerrojo al despertarse.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 49/52

Concurrencia en C++ moderno

Exclusión mutua

Mecanismos de espera

Consumidor

void productor() {for (;;) {

peticion p = genera();

unique_lock<mutex> l{m};cola.push(p);

cv.notify_one() ;}

}

Efecto de notify_one():1 Despierta a uno de los hilos esperando en la condición.

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 50/52

Concurrencia en C++ moderno

Exclusión mutua

Mecanismos de espera

Resumen

The free lunch is over (o eso parece).C++ ofrece un mecanismo portable para concurrencia.Concurrencia mínima a través de tareas asíncronas yfuturos.Uso de hilos para control más detallado de laconcurrencia.Los mutex como mecanismo básico de concurrencia.Hay mucho más.

Usar una tarjeta gráfica sin usar CUDA u OpenCL?

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 51/52

Concurrencia en C++ moderno

Exclusión mutua

Mecanismos de espera

Concurrencia en C++ modernocodemotion 2014

J. Daniel Garcia

Grupo ARCOSUniversidad Carlos III de Madrid

21 de noviembre de 2014

cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected] – @usingstdcpp – @jdgarciauc3m) 52/52