Rotina em Segundo Plano

Projeto MiniGui - Biblioteca visual para Harbour/xHarbour

Moderador: Moderadores

Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Rotina em Segundo Plano

Mensagem 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
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Rotina em Segundo Plano

Mensagem 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() )
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Rotina em Segundo Plano

Mensagem 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().
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Rotina em Segundo Plano

Mensagem por JoséQuintas »

Não é. Assim como ele disse, se alguém souber pra que serve, só dizer.... rs
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Claudio Soto
Colaborador
Colaborador
Mensagens: 566
Registrado em: 27 Ago 2012 12:31
Localização: Uruguay
Contato:

Rotina em Segundo Plano

Mensagem 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.
Saludos.
Dr. Claudio Soto
(Uruguay)
http://srvet.blogspot.com
Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Rotina em Segundo Plano

Mensagem 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   
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Rotina em Segundo Plano

Mensagem 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.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Claudio Soto
Colaborador
Colaborador
Mensagens: 566
Registrado em: 27 Ago 2012 12:31
Localização: Uruguay
Contato:

Rotina em Segundo Plano

Mensagem 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.
Saludos.
Dr. Claudio Soto
(Uruguay)
http://srvet.blogspot.com
Claudio Soto
Colaborador
Colaborador
Mensagens: 566
Registrado em: 27 Ago 2012 12:31
Localização: Uruguay
Contato:

Rotina em Segundo Plano

Mensagem 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
Saludos.
Dr. Claudio Soto
(Uruguay)
http://srvet.blogspot.com
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Rotina em Segundo Plano

Mensagem 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
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Claudio Soto
Colaborador
Colaborador
Mensagens: 566
Registrado em: 27 Ago 2012 12:31
Localização: Uruguay
Contato:

Rotina em Segundo Plano

Mensagem 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.
Saludos.
Dr. Claudio Soto
(Uruguay)
http://srvet.blogspot.com
Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Rotina em Segundo Plano

Mensagem 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.
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

Rotina em Segundo Plano

Mensagem 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.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Claudio Soto
Colaborador
Colaborador
Mensagens: 566
Registrado em: 27 Ago 2012 12:31
Localização: Uruguay
Contato:

Rotina em Segundo Plano

Mensagem 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.
Saludos.
Dr. Claudio Soto
(Uruguay)
http://srvet.blogspot.com
Avatar do usuário
asimoes
Colaborador
Colaborador
Mensagens: 4919
Registrado em: 26 Abr 2007 16:48
Localização: RIO DE JANEIRO-RJ

Rotina em Segundo Plano

Mensagem por asimoes »

Quintas,

Olha direitinho que a rotina tem janela sim.
►Harbour 3.x | Minigui xx-x | HwGui◄
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Responder