miércoles, 27 de julio de 2016

Esperando a los Threads. hb_threadWaitForAll & threadWait


hb_threadWaitForAll

La función hb_threadWaitForAll( ) sólo es eficaz cuando se le llama en el hilo principal de la aplicación.
Lo que hace es suspender el hilo principal hasta que el resto de hilos en ejecución  terminen.
En el ejemplo anterior, podemos ver como solucionar el problema anterior;

#include "hbthread.ch"

proc main()
  cls
 
  s_p1 := s_p2 := s_p3 := 0
  ? "Llama"
 hb_threadDetach(  hb_threadStart( @p1(), "sin nada" ) )

  ? "Salimos"
  hb_threadWaitForAll()
    
return

proc p1( ctext )
  Local h

   h := fcreate("test.txt")
   fwrite( h, ctext)
   fclose( h )

return

Ahora debería estar el fichero con el contenido.

En el caso que explique en el post inicial, sobre la portabilidad de un sistema de mensajes,
el salir del bucle principal, antes de salir de la aplicación, está la llamada a hb_threadWaitForAll() para que se terminen los hilos que están en marcha y evitar mensajes sin procesar porque la aplicación ha finalizado.

¿ Pero , puedo esperar a un hilo en concreto a que termine su tarea ?


hb_threadWait

hb_threadWait( <pThID> | <apThID>, [ <nTimeOut> ] [, <lAll> ] ) =><nThInd>|<nThCount> 0

Espera a que se termine pThID pasado , o en su caso, un array de threads apThID.
nTimerOut indica los segundos que tiene que esperar a que se terminen los threads pasados.

Si no pasamos , se espera hasta que todos los threads pasados finalicen si está activado el tercer parámetro lAll.

Lógicamente , no se usan hilos que están unidos a través de hb_threadJoin.

Devuelve el primer índice del hilo que ha terminado, nThInd ,o si está activado lAll, la cantidad de hilos que han podido terminar en el periodo de tiempo que hemos establecido, nThCount, o 0 si no se terminó ninguno.

Un ejemplo que muestra esto es el ejemplo de Harbour /tests/mt/mttest10.prg

#include "inkey.ch"

#ifdef __PLATFORM__WINDOWS
  REQUEST HB_GT_WVT_DEFAULT
  #define THREAD_GT hb_gtVersion()
#else
  REQUEST HB_GT_STD_DEFAULT
  #define THREAD_GT "XWC"
#endif

proc main( cGT )
  local i, aThreads, n

  if ! hb_mtvm()
     ? "This program needs HVM with MT support"
     quit
  endif

  if empty( cGT )
     cGT := THREAD_GT
  endif

  if  cGT == "QTC" .and. ! cGT == hb_gtVersion()
     /* QTC have to be initialized in main thread */
     hb_gtReload( cGT )
  endif

  ? "Starting threads..."
  aThreads := {}
  for i := 1 to 3
     aadd( aThreads, hb_threadStart( @thFunc(), cGT ) )
     ? i, "=>", atail( aThreads )
  next

 // RETOCADO, para que muestre el valor de n,
  ? "Waiting for threads"
  while inkey() != K_ESC
     n := hb_threadWait( aThreads, 0.1, .T. )       
     if n == len( aThreads )
        ?? str(n,1)
        wait
        exit
     endif
     ?? str(n,1)
  enddo


proc thFunc( cGT )
  /* allocate own GT driver */
  hb_gtReload( cGT )
  if ! dbExists( "test" ) .and. dbExists( "../test" )
     use ../test shared
  else
     use test shared
  endif
  browse()
return

Este ejemplo es interesante, nos crea 3 hilos con 3 browses sobre la misma tabla , con el mismo alias, y hacer un bucle esperando la finalización de los 3 browses.

Si lo ejecutas, y te pones en la consola que muestra lo siguiente;

Como vimos, cuando devuelve cero, es que no ha finalizado ningún hilo. Si pulsamos ESC sobre la ventana de un browse, este muere, y nos pinta un 1, indicando ,de qué de los 3 threads que estamos controlando, uno ha terminado.
A continuación, volvemos a matar otro browse, vemos que muestra un 2, indicando que ya son 2 los threads terminados  y si volvemos a matar el browse que queda, veremos que ha pintado 3 y sale del bucle.



Siguiente: Id de Theads.

GTXSII. Visual Basic .NET

Estamos trabajando muy duro en intentar en soportar más lenguajes de programación para nuestra librería GtxSII, para el Suministro Inmedi...