Anuncios

Bienvenidos sean a este post, hoy veremos como usar threads.

Anuncios

En el post anterior hablamos sobre como trabajan los threads, y hoy nos centraremos en como aplicarlos. Sabemos que el main es el encargado de correr nuestro programa, y desde aqui podemos crear nuevos threads que correran simultaneamente al main thread. Para iniciar un thread debemos utilizar un objeto de tipo thread y pasar la funcion que deseamos correr en simultaneo. Vamos a analizar un ejemplo simple:

#include <iostream>
#include <thread>

void numeros_thread()
{
        auto n{0};
        while(true)
        {
                std::cout << "Thread: " << n++ << std::endl;
        }
}

int main()
{
        std::thread fondo{numeros_thread};
        auto i{0};
        while(i < 10000)
                std::cout << "Main: " << i++ << std::endl;

        return 0;
}
Anuncios

Para crear nuestro objeto thread debemos utilizar a la libreria thread. Lo primero que haremos es definir una funcion que posee un bucle infinito donde incrementara indefinidamente una variable e iniciaremos una variable. En el main, primero definimos un objeto de tipo thread y lo iniciaremos con la funcion anterior. Aqui establecemos un bucle donde mostraremos el incremento de la variable. Cada bucle mostrara un mensaje para indicar si corre en el main o en el thread. Compilemos y veamos como es la salida:

Main: 9279
Main: 9280
Main: 9281
Main: 9282
Thread: 9472
Thread: 9473
Thread: 9474
Anuncios

Esto es una porcion de los valores que muestra la salida de nuestro programa, este ira alternando entre el main thread y el nuevo. Como comentamos en el post anterior este ira alternando entre uno y otro para que puedan dar la sensacion de que corren simultaneamente, pero esto terminara de la siguiente forma:

Main: 9998
Main: 9999
terminate called without an active exception
Abortado
Anuncios

Esto ocurre porque el bucle del main thread intenta finalizar pero no lo puede hacer porque el bucle del otro thread sigue corriendo y no puede ser detenido, ocasionando la excepcion y abortando. Pero esto se puede solucionar, para ello debemos modificar el codigo de la siguiente manera:

#include <iostream>
#include <thread>

void numeros_thread()
{
        auto n{0};
        while(true)
        {
                std::cout << "Thread: " << n++ << std::endl;
        }
}

int main()
{
        std::thread fondo{numeros_thread};
        auto i{0};
        while(i < 10000)
                std::cout << "Main: " << i++ << std::endl;
        fondo.join();

        return 0;
}
Anuncios
Anuncios

Hicimos un solo cambio, que fue agregar un metodo que nos provee la clase thread como es join. Esta posibilita que el main thread espere hasta que ese thread finalice. Como mencionamos anteriormente, y continuamente, cada thread corre como una entidad independientemente de los otros. Esto lleva a que el thread principal no esperara por los otros e intentara finalizar todo. En cambio, ahora con join este esperara por una señal del otro thread para finalizar. Si lo compilan y ejecutan, veran que el programa nunca finalizara por el bucle infinito de la funcion. Tomemos el codigo anterior y hagamos el siguiente cambio:

#include <iostream>
#include <thread>

void numeros_thread()
{
        auto n{0};
        while(true)
        {
                std::cout << "Thread: " << n++ << std::endl;
        }
}

int main()
{
        std::thread fondo{numeros_thread};
        auto i{0};
        while(i < 10000)
                std::cout << "Main: " << i++ << std::endl;
        fondo.detach();

        return 0;
}
Anuncios

Esta nueva funcion hace totalmente lo opuesto a join. Esta le dice al main thread que puede finalizar sin necesidad de preocuparse del thread que este relacionado. Si lo compilan nuevamente y ejecutan sucedera lo siguiente:

Thread: 11622
Main: 9979
Main: 9980
Main: 9981
Main: 9982
Main: 9983
Main: 9984
Main: 9985
Main: 9986
Main: 9987
Main: 9988
Main: 9989
Main: 9990
Main: 9991
Main: 9992
Main: 9993
Main: 9994
Main: 9995
Main: 9996
Main: 9997
Main: 9998
Main: 9999
$
Anuncios

Observen que el thread siguio corriendo y en el main, cuando finalizo el bucle salio del programa sin necesidad de preocuparse por el otro thread. Ya tenemos dos metodos que nos permiten mantener en espera al main thread hasta que finalicen sus threads relacionados, join, y otro que nos permite terminar el thread sin importar el estado de los otros, detach. Pero tenemos mas posibilidades, para ello analicemos el siguiente ejemplo:

#include <iostream>
#include <thread>

int main()
{
        std::thread hilo{[]{
                std::cout << "Funcion lambda en el thread." << std::endl;
        }};
        hilo.join();

        return 0;
}
Anuncios

Este es un ejemplo simple donde creamos un thread y en este le pasamos una funcion lambda, tambien conocida como funcion anonima, y en la cual solo mostramos un mensaje para indicar que la funcion esta en el thread. Luego usamos a join para que el main thread espera hasta la ejecucion de la funcion lambda. Si lo compilan y ejecutan deben tener la siguiente salida:

$ ./threads
Funcion lambda en el thread.
$
Anuncios

Ya vimos como podemos pasar funciones normales, funciones anonimas y como manejar al main principal. Pero tenemos una posibilidad mas, para ello veamos el siguiente codigo:

#include <iostream>
#include <thread>

class Test
{
public:
        Test() = default;
        void operator()() {
                ++estado;
                std::cout << estado << std::endl;
        }
private:
        int estado = 0;
};

int main()
{
        std::thread hilo{Test()};
        hilo.join();

        return 0;
}
Anuncios

En este codigo veremos como podemos usar objetos de clases llamables. Para ello definimos una clase donde haremos una sobrecarga del operador (). En esta incrementaremos a la propiedad privada llamada estado en cada llamado, y la mostraremos. En el main, creamos un objeto de tipo thread y lo iniciaremos con la clase y usamos al operador de funcion para que sea invocado. Y luego tenemos el join para que el main thread espera a que finalice la operacion anterior. Compilemos y veamos como es la salida:

$ ./threads
1
$
Anuncios

Esto ultimo que vimos es una excelente, y practica, manera de poder llevar un control de los estados de un thread. Pero esto es solo el comienzo, en los proximos posts veremos unos temas mas profundos y como podemos aplicarlo en otros temas.

Anuncios

En resumen, hoy hemos visto como usar threads, cual es la herramienta que lo permite, como se crea, como se aplica, asi como algunos problemas que pueden surgir, y los metodos que nos permiten manejar de mejor forma a los threads y un par de particularidades mas. Espero les haya resultado de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Donation

It’s for maintenance of the site, thanks!

$1.50