En este segundo capitulo pretendo mostrar como se crean threads. Un thread, como expliqué en el anterior artículo, es un objeto de la clase boost::thread, asi que al crearlo se llama al constructor.
Al crearlo, como parámetro de entrada le damos una función que es la que ejecutaremos en un thread separado.
void func1() { //hacer algo aqui } int main() { boost::thread t(func1); t.join(); }
Aunque tambien podemos usar functors para indicar al thread que tarea ejecutar.
class complexFunc2 { void operator()() const { //hacer algo complejo aqui. } }; int main() { boost::thread t(complexFunc2); t.join(); }
Hay algo que es importante. El parametro que le pasamos a un thread entra por copia y no por referencia. Una vez finaliza el thread, el objeto que le hemos pasado por copia es destruido. Esta operacion no tiene ningún peligro excepto si entre tus datos miembro tienes punteros, y el destructor los intenta borrar, asi que cuidado.
Por ejemplo:
class complexFunc3 { int& number; complexFunc3(int& _number):number(_number){} void operator()() const { for(int i = 0; i < 10000; i++) printf("%d\n",number); } }; int main() { int myVar = 2; boost::thread t(complexFunc2(myVar)); }
Una vez acaba el main, el thread principal (nuestro programa principal siempre es un thread) acaba y libera recursos. En este caso myVar es destruida. Probablemente en una de las iteraciones del bucle, printf fallará porque myVar ha dejado de existir, y por tanto number es una referencia a un número que ya no existe, y fallará.
Para evitarlo deberiamos llamar al método join(), para que el main espere la finalización de thread antes de salir. El join deberia ser llamado si al final de una funcion o dentro de la excepcion. Esto es:
int main() { int myVar = 2; boost::thread t(complexFunc2(myVar)); try{ // Algunas operaciones que pueden gnerar excepcion. } catch() { t.join(); throw; } t.join(); }
Nos puede ser útil tambien hacer lo contrario y es separar definitivamente el thread del principal. Para ello primero debemos comprobar que hay un thread para separar, o para juntar en caso de que vayamos a usar join. Para comprobarlo usamos t.joinable(), y si sale true es que podemos hacer un detach().
int main() { boost::thread t(func); if(t.joinable()) t.detach(); }Por ultimo, explico que pasar parámetros a un thread es trivial.
void func(int i, float f){} int main() { boost::thread t(func,2,2.5f); t.join(); }
Pero no hay que olvidar que los parametros se copian y que al final de la ejecución son destruidos asi que hay que tener en cuenta que enviamos y que pasará cuando sean destruidos, o que pasará cuando la función que crea el thread finalice y destruya las funciones creadas alli y el thread siga en marcha.
Pues aqui llega el final de este post, aunque todavia me queda un largo camino con los threads.
No hay comentarios:
Publicar un comentario