Página 2 de 4

Rotina em Segundo Plano

Enviado: 28 Mar 2017 13:02
por asimoes
Eu uso HB_THREAD_INHERIT_MEMVARS, o que me chamou atenção foi HB_THREAD_MEMVARS_COPY, por isso questionei o que é cada tipo

Rotina em Segundo Plano

Enviado: 28 Mar 2017 17:30
por JoséQuintas
Faz anos que não uso isso, só deixei anotação no fonte.
Encontrei texto aqui:

http://xthefull.blogspot.com.br/2016/07 ... vatos.html
Ahora , también a la hora de crear un thread , podemos definir la visibilidad de las variables
dentro del hilo.  Fichero hbthread.ch

#define HB_THREAD_INHERIT_PUBLIC    1
Indica que las variables  públicas son compartidas por todos los hilos

#define HB_THREAD_INHERIT_PRIVATE   2
Indica que las variables  privadas son compartidas por todos los hilos

#define HB_THREAD_INHERIT_MEMVARS   3
Indica que las variables privadas y públicas son compartidas por todos los hilos

#define HB_THREAD_MEMVARS_COPY      4
Indica que lo que se envía es una copia , no la variable en sí.

hb_threadStart( HB_THREAD_INHERIT_PUBLIC, @Process(), Self ) )
otro ejemplo ;
hb_threadStart( HB_BITOR( HB_THREAD_INHERIT_MEMVARS + ;
                         HB_THREAD_MEMVARS_COPY ), ;
                         @thFunc() )

Rotina em Segundo Plano

Enviado: 28 Mar 2017 18:16
por JoséQuintas
Achei curiosa esta parte
Explica como faz, só não sabe pra que serve... rs

http://xthefull.blogspot.com.br/2016/07 ... etach.html
De todas maneras, no sé exactamente cuál es el propósito del detach en Harbour si llamando  a hb_threadStart() realiza la misma función, sin usar Join, al menos, en las pruebas
que he realizado no logro ver diferencias entre crear un hilo, y crear un hilo y dejarlo morir  y llamar a detach. ( Si alguien lo sabe, bienvenida explicación )
Se for o que estou pensando, pode ser interessante.
Precisa teste, mas só imagino que seja deixar a thread separada de Main(), como se fosse uma Main2()..
Se for isso, elimina o uso de hb_ThreadWaitForAll().

Rotina em Segundo Plano

Enviado: 28 Mar 2017 18:27
por JoséQuintas
Não é. Assim como ele disse, se alguém souber pra que serve, só dizer.... rs

Rotina em Segundo Plano

Enviado: 28 Mar 2017 19:04
por Claudio Soto
JoséQuintas escreveu:Achei curiosa esta parte
Explica como faz, só não sabe pra que serve... rs

http://xthefull.blogspot.com.br/2016/07 ... etach.html
De todas maneras, no sé exactamente cuál es el propósito del detach en Harbour si llamando a hb_threadStart() realiza la misma función, sin usar Join, al menos, en las pruebas
que he realizado no logro ver diferencias entre crear un hilo, y crear un hilo y dejarlo morir y llamar a detach. ( Si alguien lo sabe, bienvenida explicación )
Se for o que estou pensando, pode ser interessante.
Precisa teste, mas só imagino que seja deixar a thread separada de Main(), como se fosse uma Main2()..
Se for isso, elimina o uso de hb_ThreadWaitForAll().
Cuando se crea un thread el SO devuelve un handle que identifica al thread. Cuando el thread termina mientras no se cierra ese handle el SO mantiene en memoria información sobre ese thread. Lo que hace el detach es precisamente cerrar ese handle y en consecuencia permitir que el SO remueva la información de ese thread de la memoria cuando el thread termine.

Si luego de crear un thread no necesitamos realizar ninguna operación con el handle del thread (ej. hacer un join con otros thread, obtener el valor devuelto al terminar el thread, etc.) llamamos a detach con dicho handle y de esa manera cuando el thread termine el SO remueva inmediatamente de la memoria la información de ese thread y así liberar recursos del sistema.

Rotina em Segundo Plano

Enviado: 28 Mar 2017 19:37
por asimoes
Quintas,

Não uso hb_ThreadWaitForAll() faço assim:

Código: Selecionar todos

   nThread := hb_ThreadStart( HB_BITOR( HB_THREAD_INHERIT_PUBLIC, ;
                                        HB_THREAD_INHERIT_PRIVATE, ;
                                        HB_THREAD_INHERIT_MEMVARS ), ;
                                        { || ::Download( "DROPBOX" + hb_PS() ) } )

   ::WaitThread( nThread )

METHOD WaitThread( nThread ) CLASS ClMonitor
   DO WHILE .T.
      IF hb_ThreadWait( nThread, 0.1, .T. ) == 1 
         EXIT
      ENDIF
      DO EVENTS
   ENDDO
RETURN Nil   

Rotina em Segundo Plano

Enviado: 28 Mar 2017 19:47
por JoséQuintas
Eu usava assim antes, inclusive um array pra controlar várias threads.
hb_ThreadWaitForAll() já aguarda tudo de uma vez.

imagine sua rotina nesta situação:

Código: Selecionar todos

PROCEDURE Main
   hb_ThreadStart( { || teste() } )
   hb_ThreadStart( { || teste() } )
   hb_ThreadStart( { || teste() } )
   hb_ThreadWaitForAll()
A informacão do Dr Claudio Soto me deixou na dúvida sobre SEMPRE usar hb_ThreadDetach()
Não sei se afetaria o teste de hb_ThreadWaitForAll()
Também não sei que tipo de recurso é armazenado, se isso é muito ou pouco no contexto geral.

Rotina em Segundo Plano

Enviado: 28 Mar 2017 20:00
por Claudio Soto
JoséQuintas escreveu:Eu usava assim antes, inclusive um array pra controlar várias threads.
hb_ThreadWaitForAll() já aguarda tudo de uma vez.

imagine sua rotina nesta situação:

Código: Selecionar todos

PROCEDURE Main
   hb_ThreadStart( { || teste() } )
   hb_ThreadStart( { || teste() } )
   hb_ThreadStart( { || teste() } )
   hb_ThreadWaitForAll()
A informacão do Dr Claudio Soto me deixou na dúvida sobre SEMPRE usar hb_ThreadDetach()
Não sei se afetaria o teste de hb_ThreadWaitForAll()
Também não sei que tipo de recurso é armazenado, se isso é muito ou pouco no contexto geral.
A nivel del SO el detach no tendría porque afectar hb_ThreadWaitForAll, pero como todas las funciones de hb son un wrappler para las funciones de thread a nivel de C, hb podría combinar varias funciones C en una función de hb, abría que ver como hb implementa en los fuentes.

Para pocos thread llamar o no el detach no creo que haga mucha diferencia, de todas formas cuando el proceso termina todo lo referente a los thread se limpia.
El detach es importante en casos que se crean muchos thread, como por ejemplo en un servidor que crea un thread por cada petición de los clientes, si existe mucha concurrencia la basura en memoria podría ser considerable.

Rotina em Segundo Plano

Enviado: 28 Mar 2017 20:30
por Claudio Soto
asimoes escreveu:

Código: Selecionar todos

   nThread := hb_ThreadStart( HB_BITOR( HB_THREAD_INHERIT_PUBLIC, ;
                                        HB_THREAD_INHERIT_PRIVATE, ;
                                        HB_THREAD_INHERIT_MEMVARS ), ;
                                        { || ::Download( "DROPBOX" + hb_PS() ) } )
Cuidado con la combinación OR de Inherit, están definidos como:

Código: Selecionar todos

#define HB_THREAD_INHERIT_PUBLIC         1 Binario   0001
#define HB_THREAD_INHERIT_PRIVATE       2                 0010
#define HB_THREAD_INHERIT_MEMVARS   3                 0011
#define HB_THREAD_MEMVARS_COPY       4                  0100
En consecuencia HB_THREAD_INHERIT_MEMVARS es siempre una combinación de HB_THREAD_INHERIT_PUBLIC y HB_THREAD_INHERIT_PRIVATE, si se usa el hb_bitOR no hay problema porque

Código: Selecionar todos

HB_BITOR( HB_THREAD_INHERIT_PUBLIC,  HB_THREAD_INHERIT_PRIVATE,  HB_THREAD_INHERIT_MEMVARS )
siempre va dar como resultado 3, pero si en cambio si se usa + en vez del OR lógico

Código: Selecionar todos

HB_THREAD_INHERIT_PUBLIC +  HB_THREAD_INHERIT_PRIVATE + HB_THREAD_INHERIT_MEMVARS 
eso da 6 que en binario es 0110 que es la combinación logica de

Código: Selecionar todos

HB_THREAD_INHERIT_PRIVATE + HB_THREAD_INHERIT_MEMVARS
Lo cual podría dar resultados diferentes al esperado.

PD: en algún lugar donde no recuerdo vi sumar estos parámetros en vez de usar el or lógico

Rotina em Segundo Plano

Enviado: 28 Mar 2017 23:40
por JoséQuintas
É esquisito isso de binário, mas é interessante.
&nbspCOPY(4)&nbsp&nbspPRIVATE(2)&nbsp&nbspPUBLIC(1)&nbsp&nbspdecimal&nbsp&nbspcombinação&nbsp
&nbsp0&nbsp&nbsp0&nbsp&nbsp1&nbsp&nbsp1&nbsp&nbspPUBLIC&nbsp
&nbsp0&nbsp&nbsp1&nbsp&nbsp0&nbsp&nbsp2&nbsp&nbspPRIVATE&nbsp
&nbsp0&nbsp&nbsp1&nbsp&nbsp1&nbsp&nbsp3&nbsp&nbspMEMVAR (PUBLIC + PRIVATE)&nbsp
&nbsp1&nbsp&nbsp0&nbsp&nbsp1&nbsp&nbsp5&nbsp&nbspPUBLIC,COPY&nbsp
&nbsp1&nbsp&nbsp1&nbsp&nbsp0&nbsp&nbsp6&nbsp&nbspPRIVATE,COPY&nbsp
&nbsp1&nbsp&nbsp1&nbsp&nbsp1&nbsp&nbsp7&nbsp&nbspMEMVAR (PUBLIC=PRIVATE),COPY&nbsp
o Bit_Xor() acaba funcionando como um liga/desliga de cada bit, combinando os elementos.
A tabela mostra em bits, e o equivalente decimal.

PUBLIC + PRIVATE + MEMVAR equivale a 1 + 2 + 3 = 6
Mas usando bit_Xor(), equivale a 3

É como se o número fosse um array de verdadeiro/falso, .T. ou .F.
E o hb_BitXor() comparasse cada elemento com .OR.

Código: Selecionar todos

numero1[ 1 ] := .T.
numero1[ 2 ] := .T.
numero1[ 3 ] := .T.
numero2[ 1 ] := .T.
numero2[ 2 ] := .T.
numero2[ 3 ] := .T.

resultado[ 1 ] := numero1[ 1 ] .OR. numero2[ 1 ]
resultado[ 2 ] := numero1[ 2 ] .OR. numero2[ 2 ]
resultado[ 3 ] := numero1[ 3 ] .OR. numero2[ 3 ]
Acho que a diferença é que é mais rápido comparar do que somar.
E também porque desse jeito, não precisou nem de 1 caractere pra guardar toda informação, já que 1 caractere ocupa 8 bits, e aí só usou 3.

Se fazendo isso já precisamos 4GB de memória... imaginem se isso não fosse feito.... rs

Rotina em Segundo Plano

Enviado: 29 Mar 2017 00:25
por Claudio Soto
Exactamente, en el álgebra booleana el OR funciona como un enciende bits mientras que el AND obtiene cuales son los bits encendidos.

Origen (operador booleano) Patron = Destino

OR: si alguno o todos los bits estan encendidos retorna 1
0 | 0 = 0
1 | 0 = 1
0 | 1 = 1
1 | 1 = 1

AND: retorna 1 solo si ambos bits estan encendidos
0 & 0 = 0
1 & 0 = 0
0 & 1 = 0
1 & 1 = 1

XOR: (exclusive OR) retorna 1 solo si uno solo de los bits está encendido
0 ^ 0 = 0
1 ^ 0 = 1
0 ^ 1 = 1
1 ^ 1 = 0

NOT:
~0 = 1
~1 = 0

Además es mucho más rápido operar a nivel​ de bit que de byte. Con un byte se pueden tener 8 banderas y un total de 256 combinaciones.

Rotina em Segundo Plano

Enviado: 29 Mar 2017 05:35
por asimoes
Olá pessoal,

Usando hb_ThreadWaitForAll() e/ou WaitThread( nThread ) *

* função WaitThread listada abaixo

Vejam a mensagem no título da janela principal Teste Diversos (Não está respondendo)
Usando somente hb_ThreadWaitForAll()
Screen Shot 03-29-17 at 05.17 AM.PNG
Usando a função WaitThread() -> hb_ThreadWait()
A função Evento() pode usar hwg_DoEvents() ou DoEvents() do Dr. Claudio (HMG) https://pctoledo.org/forum/viewto ... 6&start=15
Screen Shot 03-29-17 at 05.27 AM.PNG

Código: Selecionar todos

FUNCTION MAIN()

     nThread := hb_ThreadStart( HB_BITOR( HB_THREAD_INHERIT_PUBLIC, ;
                                        HB_THREAD_INHERIT_PRIVATE, ;
                                        HB_THREAD_INHERIT_MEMVARS ), ;
                                        { || Teste() } )
                                        
     //hb_ThreadWaitForAll()
     
     WaitThread( nThread )
     
RETURN Nil

FUNCTION Teste()
LOCAL oCrt
  
   oCrt := WvgCrt():New()
   oCrt:lModal  := .T.
   oCrt:visible := .T.
   oCrt:create()
   oCrt:resizable := .F.
   
   Hb_GTInfo( HB_GTI_WINTITLE, "Teste com Thread" )
    
   FOR I:=1 TO 3000000
      @ 0,0 SAY StrZero( I, 7 ) 
   NEXT
   
   oCrt:destroy()
   
RETURN Nil

FUNCTION WaitThread( nThread )
   DO WHILE .T.
      IF hb_ThreadWait( nThread, 0.1, .T. ) == 1 
         EXIT
      ENDIF
      Evento()
   ENDDO
RETURN Nil   

FUNCTION Evento()
   hwg_DoEvents() /ou DoEvents() 
RETURN .T.

Rotina em Segundo Plano

Enviado: 29 Mar 2017 09:37
por JoséQuintas
Isso é sério ou é piada?

Evento pra janela não travar, numa rotina que não tem janela.

Além disso, na gtwvg basta Inkey() na rotina que tem janela.

E mais que isso: a thread principal pode ser responsável por todo o funcionamento de todo o aplicativo, todas as janelas e todos os eventos.
Congelar a Main, na maioria dos casos, é travar o aplicativo.

Rotina em Segundo Plano

Enviado: 29 Mar 2017 10:48
por Claudio Soto
asimoes escreveu:Olá pessoal,

Usando hb_ThreadWaitForAll() e/ou WaitThread( nThread ) *

* função WaitThread listada abaixo

Vejam a mensagem no título da janela principal Teste Diversos (Não está respondendo)
Usando somente hb_ThreadWaitForAll()
Screen Shot 03-29-17 at 05.17 AM.PNG
Usando a função WaitThread() -> hb_ThreadWait()
A função Evento() pode usar hwg_DoEvents() ou DoEvents() do Dr. Claudio (HMG) https://pctoledo.org/forum/viewto ... 6&start=15
Screen Shot 03-29-17 at 05.27 AM.PNG

Código: Selecionar todos

FUNCTION MAIN()

     nThread := hb_ThreadStart( HB_BITOR( HB_THREAD_INHERIT_PUBLIC, ;
                                        HB_THREAD_INHERIT_PRIVATE, ;
                                        HB_THREAD_INHERIT_MEMVARS ), ;
                                        { || Teste() } )
                                        
     //hb_ThreadWaitForAll()
     
     WaitThread( nThread )
     
RETURN Nil

FUNCTION Teste()
LOCAL oCrt
  
   oCrt := WvgCrt():New()
   oCrt:lModal  := .T.
   oCrt:visible := .T.
   oCrt:create()
   oCrt:resizable := .F.
   
   Hb_GTInfo( HB_GTI_WINTITLE, "Teste com Thread" )
    
   FOR I:=1 TO 3000000
      @ 0,0 SAY StrZero( I, 7 ) 
   NEXT
   
   oCrt:destroy()
   
RETURN Nil

FUNCTION WaitThread( nThread )
   DO WHILE .T.
      IF hb_ThreadWait( nThread, 0.1, .T. ) == 1 
         EXIT
      ENDIF
      Evento()
   ENDDO
RETURN Nil   

FUNCTION Evento()
   hwg_DoEvents() /ou DoEvents() 
RETURN .T.
Aunque sea en modo consola siempre se crea una ventana, en Windows todo es una ventana, un botón, un menú, un cuadro de diálogo, etc. y en consecuencia cada uno esta asociado a una cola de mensajes. Además si mal no recuerdo las gt crean ventanas de Windows.

Para poder usar hb_ThreadWaitForAll en este ejemplo habría que poner un DoEvents dentro del for

FOR I:=1 TO 3000000
@ 0,0 SAY StrZero( I, 7 )
NEXT

Hay que recordar siempre que los threads son funciones común y corriente cuya única ventaja es que se pueden ejecutar en simultáneo a diferencia de las funciones tradicionales que son secuenciales.

Rotina em Segundo Plano

Enviado: 29 Mar 2017 11:04
por asimoes
Quintas,

Olha direitinho que a rotina tem janela sim.