C++ Builder proporciona la clase abstracta TThread para la creación de hebras.
Para definir una hebra se debe crear un descendiente de TThread, para lo cual se ha de crear una clase derivada de TThread. Para facilitar el trabajo, C++Builder incluye un asistente que lo hace por nosotros.
Ejemplo: Crear una hebra
Abrimos el repositorio en su página New (al que se accede desde la opción del menú File->New...). Seleccionamos el elemento Thread Object. Denominamos THebraPelota a la clase derivada de TThread. Ya hemos creado nuestra primera hebra en una unidad independiente (que almacenaremos en los ficheros HPelota.cpp y HPelota.h). |
La clase TThread es abstracta porque posee un método virtual puro denominado Execute(), que será el que rellenemos con el código asociado a la hebra.
Como sucede con cualquier otra clase, en una clase derivada de TThread se pueden añadir todos los miembros (propiedades y métodos) que se necesiten. Obligatoriamente sólo hay que implementar:
La inicialización de una hebra se realiza en su constructor, donde se establecen los valores iniciales de cuantas propiedades sean necesarias.
Antes de invocar al constructor de una clase derivada de TThread, se invoca al constructor de su clase base (TThread):
__fastcall TThread(bool CreateSuspended);
Éste recibe como parámetro false si deseamos que la hebra se ejecute inmediatamente después de ser creada o true si queremos que quede suspendida inicialmente.
Dos características de las hebras conviene establecerlas en el constructor: su prioridad y cuándo debe liberarse la hebra.
La prioridad de una hebra indica qué grado de preferencia tiene la hebra cuando el sistema operativo reparte el tiempo de CPU entre las distintas hebras que se estén ejecutando en el sistema.
Para indicar la prioridad del objeto de hebra hay que fijar el valor de la propiedad Priority:
Valor | Prioridad |
tpIdle | Se ejecuta cuando el sistema está inactivo. |
tpLowest | Dos puntos por debajo del valor normal. |
tpLower | Un punto por debajo del valor normal. |
tpNormal | La hebra tiene la prioridad normal. |
tpHigher | Un punto por encima del valor normal. |
tpHighest | Dos puntos por encima del valor normal. |
tpTimeCritical | La hebra tiene la prioridad más alta. |
Si se aumenta mucho la prioridad de una hebra que requiera muchos recursos (vg: CPU) puede ocurrir que las demás hebras de la aplicación (y del sistema) no lleguen a procesarse a la velocidad adecuada.
Ejemplo:
Si tenemos un proceso que consume una cantidad considerable de tiempo de CPU, puede ser interesante dar la posibilidad al usuario de cancelar el proceso durante su ejecución. Esto se puede conseguir creando una hebra con prioridad normal para ese proceso y otra hebra de alta prioridad que únicamente esté a la espera de que el usuario pulse un botón de cancelación. La hebra de alta prioridad no consumirá tiempo de CPU porque estará bloqueada pero, en el caso de que el usuario pulse el botón, responderá rápidamente. |
A menudo las hebras de una aplicación se ejecutan una sola vez. Si este es el caso, lo más sencillo es dejar que el objeto hebra se libere a sí mismo, estableciendo la propiedad FreeOnTerminate a true.
Sin embargo, hay casos en que el objeto hebra representa una tarea que debe realizarse varias veces. Si la aplicación requiere varias instancias del mismo objeto hebra (para ejecutar la hebra varias veces), se puede aumentar el rendimiento de la aplicación almacenando las hebras en una caché para utilizarlas más adelante, en lugar de destruirlas y crearlas de nuevo cada vez. Para ello, basta con fijar el valor de la propiedad FreeOnTerminate a false. En este caso, será responsabilidad del programador la liberación de la hebra.
MUY IMPORTANTE:
|
Ejemplo:
#include "ObjGraf.h"En la clase THebraPelota:... public: TPelota *Pelota; __fastcall THebraPelota(TPaintBox *PaintBox); __fastcall ~THebraPelota(void); ... #include <stdlib.h> ... __fastcall THebraPelota::THebraPelota (TPaintBox *PaintBox) : TThread(false) { Priority = tpNormal; FreeOnTerminate = true; Pelota = new TPelota ( // Objeto pelota... PaintBox, // ...aletorio. (TColor)(random(0xFF) | (random(0xFF)*0x100) | (random(0xFF)*0x10000)), random(PaintBox->Width), random(PaintBox->Height), random(20)+1, TDireccion((random(2)+1) | (random(2)+1)*4)); } __fastcall THebraPelota::~THebraPelota(void) { delete Pelota; } |