Página 1 de 2
Duvida sobre Thread (Hb_ThreadStart)
Enviado: 23 Fev 2021 11:31
por asimoes
Tenho esse teste com uma Thread usando os parâmetros HB_BITOR
A função recebe lContinua .T., funciona.
Mas se eu quiser trocar o valor para lContinua := .F., a Thread continua com o valor da variável lContinua com .T.
Tem como intervir nos valores em uma thread?
no DO WHILE lContinua
Código: Selecionar todos
PUBLIC lContinua := .T.
nThread := Hb_ThreadStart( HB_BITOR( HB_THREAD_INHERIT_PUBLIC, ;
HB_THREAD_INHERIT_PRIVATE, ;
HB_THREAD_INHERIT_MEMVARS, ;
HB_THREAD_MEMVARS_COPY ), ;
{ || Teste() } )
lContInua := .F.
FUNCTION Teste()
LOCAL nRow AS NUMERIC, nCol AS NUMERIC
nCol := Col()
nRow := Row()
nSeconds := Seconds()
DO WHILE lContinua
Hb_IdleSleep( 1 )
IF (Seconds() - nSeconds) > 5
nSeconds := Seconds()
cTime := Time()
IF File( "TIME.TXT" )
cTime := Hb_MemoRead( "TIME.TXT" ) + Hb_Eol() + cTime
ENDIF
Hb_MemoWrit( "TIME.TXT" , cTime )
ENDIF
hwg_DoEvents()
ENDDO
WAPI_BRINGWINDOWTOTOP( Hb_gtInfo( HB_GTI_WINHANDLE ) )
Quit
RETURN Nil
Duvida sobre Thread (Hb_ThreadStart)
Enviado: 23 Fev 2021 12:07
por JoséQuintas
Não, só se for PUBLIC.
Uma opção é criar classe e/ou função.
Código: Selecionar todos
FUNCTION AppUserName( cValue )
STATIC cAppUserName := ""
IF cValue != Nil
cAppUserName := cValue
ENDIF
RETURN cAppUserName
Desse jeito, usa AppUserName(), ou AppUserName( "JOSE" ), tanto faz a thread.
Acaba sendo bom, porque a compilação vai avisar se escrever errado.
Também pode ser array.
Classe... não é tão bom, porque não vai ter checagem de nome errado.
Duvida sobre Thread (Hb_ThreadStart)
Enviado: 23 Fev 2021 12:15
por JoséQuintas
Veja se é uma coisa parecida com esta que está querendo:
Código: Selecionar todos
CREATE CLASS RunWhileThreadClass
VAR lExit INIT .F.
VAR nThreadId
VAR nInterval INIT 600
VAR cWindowTitle INIT ""
VAR bCode
METHOD New() INLINE ::nThreadId := hb_ThreadSelf(), SELF
METHOD Execute( bCode )
ENDCLASS
METHOD Execute( bCode ) CLASS RunWhileThreadClass
LOCAL nCont
hb_gtReload( "WVG" )
IF bCode != NIL
::bCode := bCode
ENDIF
AppInitSets()
HB_GtInfo( HB_GTI_WINTITLE, ::cWindowTitle )
wvgSetAppWindow():Hide()
DO WHILE ! ::lExit
Eval( ::bCode )
FOR nCont = 1 TO ::nInterval
hb_ReleaseCPU()
IF hb_ThreadWait( ::nThreadId, 0.1, .T. ) == 1
::lExit := .T.
ENDIF
Inkey(1)
IF ::lExit
EXIT
ENDIF
NEXT
ENDDO
RETURN NIL
O que isso faz?
a thread vai ficar rodando, enquanto a thread que a chamou continuar ativa.
Opcionalmente, se alterar lExit := .T. ela encerra assim que possível.
Exemplo:
Código: Selecionar todos
oClasse := RunWHileThreadClass():New()
oClasse:bCode := { || Any() }
hbThreadStart( { || oClasse:Execute() } )
...
oClasse:lExit := .T.
Usei isso, por exemplo, em pedidos.
Enquanto o usuário estava na digitação de pedidos, aparecia alerta avisando de atrasos.
Saiu de pedidos, a rotina também encerrava automático. (nesse caso não precisava oClasse:lExit := .T.)
E qualquer coisa da classe, fica visível de qualquer thread.
São assim os controles Windows/GUI, só pra curiosidade.
Duvida sobre Thread (Hb_ThreadStart)
Enviado: 23 Fev 2021 12:20
por JoséQuintas
O cuidado com threads sobre compartilhar variáveis é grande.
Imagine o usuário num relatório escolhendo impressora, e em outro lugar também escolhendo impressora.
Se a variável for pública, um relatório vai alterar a impressora do outro.
Outro caso, um array:
Uma thread tá trabalhando com o array de um tamanho, e a outra thread altera esse tamanho.
E não só array, de repente uma string de tamanho 30 vira tamanho 10... se for no momento exato de pegar o conteúdo, o estrago pode ser grande, porque invade área da memória que não pertence à variável.
Nessas situações é onde precisa um cuidado a mais, o tal Mutex() que seria parecido com RLock(), mas pra variáveis.
Isso evita que o conteúdo seja alterado por outra thread durante o uso.
Duvida sobre Thread (Hb_ThreadStart)
Enviado: 23 Fev 2021 13:27
por asimoes
QUintas,
Entendi isso é muito pontual, enfim valeu pela dica
Duvida sobre Thread (Hb_ThreadStart)
Enviado: 23 Fev 2021 13:29
por asimoes
Quintas,
faltou a função AppInitSets()
Duvida sobre Thread (Hb_ThreadStart)
Enviado: 23 Fev 2021 13:52
por JoséQuintas
asimoes escreveu:faltou a função AppInitSets()
Uso essa pra configurar meu default.
Em thread precisa configurar RDDSetDefault(), SET DATE, e outras coisas, como se fosse outro EXE.
Então só criar com os seus defaults.
Nota: Usei um nome que achei adequeado, inicia os "sets" do aplicativo, por isso chamei AppInitSets()
Duvida sobre Thread (Hb_ThreadStart)
Enviado: 23 Fev 2021 16:15
por asimoes
Quintas,
Aproveitando parte da sua classe, consegui simular o que eu queria debugando pra saber o conteúdo do arquivo time.txt
A função teste recebeu a troca da variável lExit depois de executada
Código: Selecionar todos
CREATE CLASS RunWhileThreadClass
VAR lExit INIT .F.
METHOD New() INLINE SELF CONSTRUCTOR
ENDCLASS
PUBLIC oClasse := RunWHileThreadClass():New()
nThread := Hb_ThreadStart( HB_BITOR( HB_THREAD_INHERIT_PUBLIC, ;
HB_THREAD_INHERIT_PRIVATE, ;
HB_THREAD_INHERIT_MEMVARS, ;
HB_THREAD_MEMVARS_COPY ), ;
{ || Teste() } )
Inkey(0)
oClasse:lExit := .T.
FUNCTION Teste()
LOCAL nRow AS NUMERIC, nCol AS NUMERIC
nSeconds := Seconds()
DO WHILE ! oClasse:lExit
Hb_IdleSleep( .1 )
IF (Seconds() - nSeconds) > 5
nSeconds := Seconds()
cTime := Time()
IF File( "TIME.TXT" )
cTime := Hb_MemoRead( "TIME.TXT" ) + Hb_Eol() + cTime
ENDIF
Hb_MemoWrit( "TIME.TXT" , cTime )
ENDIF
hwg_DoEvents()
ENDDO
Quit
RETURN Nil
Duvida sobre Thread (Hb_ThreadStart)
Enviado: 23 Fev 2021 22:53
por JoséQuintas
Só um comentário:
Porque não uma janela executando alguma coisa?
Duvida sobre Thread (Hb_ThreadStart)
Enviado: 24 Fev 2021 10:49
por asimoes
JoséQuintas escreveu:Só um comentário:
Porque não uma janela executando alguma coisa?
O meu teste é conseguir debugar o sistema enquanto a thread está sendo executada, dessa forma eu consigo debugar enquanto a thread está rodando e atribuir oClasse:lExit := .T. a qualquer momento no meu teste por fora da thread para interromper a sua execução, nesse teste eu não preciso de janela na thread
O interessante não sei se é uma limitação ou falha só consegui interromper a thread com uma variável de classe, uma variável publica tipo public lExit := .F. e depois de executada a thread modificando para lExit para .f. , não funciona, somente com variável da classe
Duvida sobre Thread (Hb_ThreadStart)
Enviado: 24 Fev 2021 12:02
por JoséQuintas
Se é só por causa da variável, usa a outra opção.
Código: Selecionar todos
FUNCTION AbortRun( lAbort )
STATIC sAbort := .F.
IF lAbort != Nil .AND. lAbort
sAbort := .T.
ENDIF
RETURN sAbort
Na rotina:
E quando precisar:
A não ser que vão ter várias situações diferentes ao mesmo tempo.
Duvida sobre Thread (Hb_ThreadStart)
Enviado: 24 Fev 2021 13:07
por asimoes
Quintas,
A sua alternativa também resolver, vlw
Duvida sobre Thread (Hb_ThreadStart)
Enviado: 24 Fev 2021 13:29
por asimoes
Aquintas,
Não funcionou
Troquei o oClasse:lExit no while por AbortRun()
Antes da chamada da Thread
AbortRun( .F. )
DO WHILE ! AbortRun() //oClasse:lExit
Depois da chamada da Thread AbortRun( .T. )
O loop da Thread continuou rodando, só funciona com oClasse:lExit
Duvida sobre Thread (Hb_ThreadStart)
Enviado: 24 Fev 2021 13:37
por asimoes
Completando:
Assim funciona, usando a função AbortRun() não
Código: Selecionar todos
oClasse:lExit := .F.
fErase( "TIME.TXT" )
nThread := Hb_ThreadStart( HB_BITOR( HB_THREAD_INHERIT_PUBLIC, ;
HB_THREAD_INHERIT_PRIVATE, ;
HB_THREAD_INHERIT_MEMVARS, ;
HB_THREAD_MEMVARS_COPY ), ;
{ || Teste() } )
altd()
oClasse:lExit := .T.
13:35:06
13:35:11
13:35:16
FIM
O FIM siginifica que saiu do while
Duvida sobre Thread (Hb_ThreadStart)
Enviado: 24 Fev 2021 15:59
por Claudio Soto
Alexandre probá sin el parámetro HB_THREAD_MEMVARS_COPY
Porque si mal no recuerdo HB_THREAD_MEMVARS_COPY envía una copia de la variable (paso por valor) y no la variable en sí (paso por referencia)