viernes, 29 de julio de 2016

NOTAS FINALES de Threads en Harbour


Todo lo bueno tiene un final, y esta serie sobre threads en Harbour llega a su fin.
Espero que os haya sido ameno y entrenido, tanto como yo en escribirlo.

Es importante ver los ejemplos de Harbour, son muy ilustrativos , aunque para los que no estamos acostumbrados, pueden ser un poco lioso al inicio


Listado de ejemplos de Harbour



harbour/contrib/mt/mttest1.prg
  • Muestra el uso como detached local y valores complejos usando un thread

harbour/contrib/mt/mttest2.prg
  • Muestra el uso del comando QUIT y el estamento ALWAYS en ejecución. El thread hijo usa QUITt antes que el principal

harbour/contrib/mt/mttest3.prg
  • Muestra el uso del comando QUIT y el estamento ALWAYS en ejecución. El thread main usa QUITt antes que el thread hijo

harbour/contrib/mt/mttest4.prg
  • Muestra el uso de variables protegidas y sin proteger

harbour/contrib/mt/mttest5.prg
  • Muestra el uso thread static variables

harbour/contrib/mt/mttest6.prg
  • Usando variables tipo memvar con hilos

harbour/contrib/mt/mttest7.prg
  • Ejemplo de uso de Mutex para enviar/recibir mensajes entre hilos.

harbour/contrib/mt/mttest8.prg
  • Usando el compartir variables de memoria entre hilos

harbour/contrib/mt/mttest9.prg
  • Muestra como usar el mismo alias entre distintos hilos, usando  estas 2 funciones hb_dbRequest y hb_dbDetach.
  • Nota: Un regalo de despedida lo tenéis abajo ;-)

harbour/contrib/mt/mttest10.prg
  • Muestra una consola por thread mostrando un browse

harbour/contrib/mt/mttest11.prg
  • Muestra un ejemplo de un thread asincrono mostrando un reloj

harbour/contrib/mt/mttest12.prg
  • Variables a nivel de hilo, pueden ser declaradas como;
    THREAD STATICt_Var1
    Esta variable es una variable static por cada hilo creado.

Mención especial para el código fuente /contrib/httpd/core.prg, donde podemos ver muchas de estas técnicas explicadas.

De regalo ;-)

Esto fue escrito hace ya 6 años para un sistema para hacer una indexación multihilo, aunque en la mayoría de los casos existe penalización por tema de velocidad de disco, es bueno saber COMO se podria hacer.

En más de 1000 servidores diferentes hemos encontrado que un máxima de 5 hilos por
tabla y un índice a la vez, la ganancia es sustancial en un sistema monolítico.



/*
  Example multiThreads index.
  One thread by table , and one thread by index.
  2010 Rafa Carmona

  Thread Main
       |--------->  Thhread child table for test.dbf
       |                        |----> Thread child index fname
       |                        |
       |                        |----->Thread child index fcode
       |
       |--------->  Thhread child table for test2.dbf
                               |----->Thread child index fname2


*/
#include "hbthread.ch"

proc Main( uCreate )
   Local nSeconds
   Local aFiles  := { "test", "test2" }        // Arrays files dbf
   Local aNtx    := { { "fname", "fcode" },;   // files index for test
                      { "fName2" } }           // files index for test2
   Local aExpr   := { { "name", "code" },;
                      { "dtos(fecha)+str(code)" }  }     // Expresions
   Local cDbf

   if empty( lCreate )
      lCreate := "0"
   endif

   setmode( 25,80 )
   cls

   if uCreate = "1"
      ? "Create test.dbf and test2.dbf"
      dbCreate("test",{ {"name","C",1,0 },{"code","N",7,0 } } )
      use test
      while lastRec() < 1000000
            dbAppend()
            field->name := chr( recno() )
            field->code := recno()
      enddo
      close
      dbCreate("test2",{ {"fecha","D",8,0 },{"code","N",7,0 } } )
      use test2
      while lastRec() < 1000000
            dbAppend()
            field->fecha := date() + recno()
            field->code := recno()
      enddo
      close
   endif

   cls
   // Threads
   nSeconds := Seconds()
   for each cDbf in aFiles
      ? "Process.: " + cDbf
      hb_threadStart( @aCreateIndexe(), cDbf, aNtx[ cDbf:__enumindex ],
aExpr[ cDbf:__enumindex ], cDbf:__enumindex  )
   next

   ? "Wait for threads ...."
   hb_threadWaitForAll()

   ? hb_valTostr( Seconds() - nSeconds )

   ? "finish"

return

function aCreateIndexe( cFile, aNtx, aExpr, nPosDbf )
      Local nContador := 1
      Local cFileNtx, cExpr
      Local nLong := Len( aNtx )
      Local aThreads := {}
      Local cAlias

      use ( cFile )
      cAlias := alias()
      hb_dbDetach( cAlias )  // Libero el alias

      for each cFileNtx in aNtx
          cExpr  := aExpr[ cFileNtx:__enumindex ]
          nContador := 1
          nPos := cFileNtx:__enumindex
          aadd( aThreads, hb_threadStart( @crea(), cAlias,cExpr,
cFileNtx, nPos, nPosDbf ) )
      next

      aEval( aThreads, { |x| hb_threadJoin( x ) } )  // wait threads childs
      hb_dbRequest( cAlias, , , .T.)  // Restaura el alias
      close

RETURN NIL

proc crea( cAlias, cExpr, cFileNtx, nPos, nPosDbf )
     Local nContador := 1

      hb_dbRequest( cAlias, , , .T.)  // Restaura el alias

      INDEX ON &(cExpr) TO &(cFileNtx) ;
            EVAL {|| hb_dispOutAt( nPosDbf, iif( nPos = 1, 20, 40 ),
alltrim( hb_valtostr( nContador) ), "GR+/N" ), nContador += INT(
LASTREC() / 100 ) , .T. } ;
            EVERY INT( LASTREC() / 100 )

      hb_dbDetach( cAlias )          // Libera el alias


return

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...