lunes, 25 de julio de 2016

Sincronizar Threads, hb_threadJoin()


hb_threadJoin

hb_threadJoin( <pThID> [, @<xRetCode> ] ) -> <lOK>
Bloquea el thread principal, hasta la finalización de pThID.
Se pasa una variable por referencia para obtener la respuesta de la función si fuese necesario.

Una descripción gráfica sería la siguiente, donde la llamada a hb_threadJoin , para thread1 y thread2 , bloquea el proceso principal, hasta que los 2 threads se hayan realizado.






Un ejemplo simple es lanzar una serie de hilos para precalcular datos, y esperar a que todos terminen para poder continuar.

En este ejemplo, simplemente lo metemos en un for con un delay para ver el efecto en real de lo que hace hb_threadJoin();
 
#include "hbthread.ch"
static s_p1, s_p2, s_p3

proc main()
  Local aThreads := {}
  Local oObject := Test():New()

  cls
  
  s_p1 := s_p2 := s_p3 := 0

  AAdd( aThreads, hb_threadStart( HB_THREAD_INHERIT_PUBLIC, @p1() ) )
  AAdd( aThreads, hb_threadStart( HB_THREAD_INHERIT_PUBLIC, @p2() ) )
  AAdd( aThreads, hb_threadStart( HB_THREAD_INHERIT_PUBLIC, @p3() ) )

     AAdd( aThreads, hb_threadStart( {|| oObject:&("Paint")( "From Harbour" ) } ) )

  AEval( aThreads, {| h | hb_threadJoin( h ) } )
 
  ? "Total:", s_p1 + s_p2 + s_p3
  
return

proc p1()
  local x
  for x := 1 to 5
      s_p1 := x
      DispOutAt( 1, 1, "(Thread 1):"+ Str( x,2 ) )
      hb_idleSleep( 0.5 )
  next

return

proc p2()
  local x
  for x := 1 to 5
      s_p2 := x
      DispOutAt( 2, 1, "(Thread 2):"+ Str( x,2 ) )
      hb_idleSleep( 0.5 )
  next

return

proc p3()
  local x
  
  for x := 1 to 10
      s_p3 := x
      DispOutAt( 3, 1, "(Thread 3):"+ Str( x,2 ) )
      hb_idleSleep( 0.5 )
  next

return

#include "hbclass.ch"
CLASS TEST
     METHOD New( ) CONSTRUCTOR
     METHOD Paint( cValue ) INLINE DispOutAt( 2,20, cValue )
END CLASS

METHOD New() CLASS TEST
RETURN Self   




También podéis observar como llamar al method de un objeto, en este caso , se llama a Paint de la clase Tests, pasando un valor, "From Harbour" ;

hb_threadStart( {|| oObject:&("Paint")( "From Harbour" ) } )


Este ejemplo de Harbour, /tests/mt/mttest01.prg, podemos observar cómo obtener la respuesta de la función thFunc(), en este caso, la variable xResult.

static s_var
proc main()
  local xResult
  ? Version()
  ? "join:", hb_threadJoin( hb_threadStart( @thFunc() ), @xResult )
  ? "result:", xResult
  ? "static var type:", valtype( s_var )
  ? eval( s_var )
  ? eval( s_var )
return

func thFunc()
  local i := 12345.678
  s_var := {|| i++ }
return replicate( "Hello World!!! ", 3 )