Malditos Threads (vitaminados)
Por fín, en "Programming Ape" cosas que tienen que ver con la parte "Programming" y no con la parte "Ape" del blog.
Desde que llegué de vuelta de vacaciones me he estado peleando con los hilos (threads) en VC++ 6.0. Era la primera vez que me topaba con la necesidad de ejecutar las cosas en un thread para que no me deje las ventanitas colgadas cuando algo tarda un poco. Es feo que una aplicación parezca colgada cuando solo está procesando los resultados de una query SQL.
La verdad es que la cosa es sencilla de cojones. Para crear un hilo sencillito que se ejecute en un diálogo que ya tiene su función de proceso de los datos que se le pasan solo se tienen que tener encuenta estas tres cosas:
1) La función CreateThread() para crear el thread.
2) La función TerminateThread() para matarlo cuando se salga antes de que el thread haya terminado (no se para cuando cierras el diálogo).
3) Una función desde la que se ejecute la función que ya se tiene hecha a la que se le pasan los parámetro que se ejecutan en la función vieja mediante una estructura pasada como void *.
Por ejemplo, una funcíon que inserte items en una lista y luego espere un segundo. Esto dejaría la ventana colgada si no se hace desde un thread:
la estructura que usaré:
struct argumentos {
char frasecita[256];
int num;
};
La funcíon para el thread:
DWORD WINAPI funcion_thread(LPVOID datos){
LVITEM fila;
int cont, acum;
struct argumentos *argums;
cont = 10;
argums = (struc arguentos *)datos;
for (acum = 0; acum < cont; acum++) {
char str[1024];
char *algo;
sprintf(str, "thread [%d - %d]", acum, argums->num);
memset((void *)&fila, 0, sizeof(fila));
fila.mask = LVIF_TEXT;
fila.iItem = acum;
fila.iSubItem = 0;
fila.pszText = str;
fila.cchTextMax = sizeof(fila.pszText);
SendDlgItemMessage(hDialogo, IDC_LIST, LVM_INSERTITEM,0,(LPARAM)&fila);
fila.iSubItem = 1;
fila.pszText = argums->frasecita;
fila.cchTextMax = sizeof(argums->frasecita);
SendDlgItemMessage(hDialogo, IDC_LIST, LVM_SETITEM,0,(LPARAM)&fila);
Sleep(1000);
}
return 0;
}
La llamada de thread:
struct argumentos *argums;
int id;
HANDLE hThread;
argums = (struct argumentos *)calloc(1, sizeof(struct argumentos));
strcpy(argums->frasecita, "soy una piedra");
argums->num = 12;
hThread = CreateThread(0, 0, funcion_thread, (LPVOID)argums, 0, &id);
Luego, a la hora de acabar a la fuerza con la función:
TerminateThread(hThread, 0);
Aunque la mejor opción es intentar terminar siempre el thread desde dentro con:
ExitThread(DWORD exitstatus);
Como se puede ver, la estructura de argumentos se le pasa como puntero y se recoge como tal, he intentado pasar la dirección de la estructura sin que ésta fuera un argumento, pero no me ha dejado la muy puta.
El mejor modo para saber si el Thread aún está corriendo o se ha quedado colgado o lo que sea es con la función:
BOOL GetExitCodeThread(HANDLE hThread, LPDWORD dwExitCode);