Página 1 de 1

Caixa preta de Thread

Enviado: 16 Mar 2019 15:15
por janio
Boa tarde,

Preciso executar um processo em paralelo e pra não ter que fazer outro exe resolvi tentar com thread. Tudo ocorre bem, a thread faz o que tem que fazer, porém ao voltar da thread o meu sistema apresenta erro para qualquer função chamada abortando o sistema sem qualquer aviso. O erro eh: Muitas chamadas recursivas ao manipulador de erros

Se tiro a chamada da thread, tudo volta a funcionar normalmente como sempre funcionou. Parece que ao chamar a thread, ela modifica o comportamento do sistema, sei la...

Eu só preciso que ao retornar da thread o sistema se comporte da mesma maneira
:(

Código: Selecionar todos

	...
   SET TIMER oTimer3 OF oDlgSAT VALUE (45*1000) ACTION {|| EnviaVFPeIntegrador() }

	DoEvents()
	ACTIVATE DIALOG oDlgSAT SHOW SW_SHOWMAXIMIZED

RETURN oDlgSAT:lresult

/*--------------------------------------------------------------------------------------*/

Function EnviaVFPeIntegrador

ThReadVFPeIntegrador :=  Hb_ThreadStart( Hb_BITOR( HB_THREAD_INHERIT_PUBLIC, HB_THREAD_INHERIT_PRIVATE ), { || Proces(cChvReq, cChvVal, cIdeInt, cCGCEMP) } )

Return Nil

/*--------------------------------------------------------------------------------------*/

Function Proces(pChvReq, pChvVal, pIdeInt, pCGCEMP)

DbUseArea(.t.,"MEDCDX","A20MPG","MeioPGint")
If NetErr()
	Return 
Endif

DbUseArea(.t.,"MEDCDX","A20cfe","CupomInt")
If NetErr()
	Close CupomInt
	Return 
Endif

cQuery = "SELECT * " + ;
         "FROM " + ;
        		"a20mpg " + ;
         "WHERE " + ;
        		"IS_DELETED='N' and IdFila='' and meiopg ='CARTAO POS' and nrssat!='' " + ;
         "ORDER BY " + ;
         	"datmov "
GERA_TAB()
use &dbftmp as cQuery NEW SCROLLABLE

If Reccount() > 0

	DbGoTop()

	pVlrCup := TotPed
	pVlrCrt := VlrPag
	pSerPos := AllTrim(SerPos)
	pNumPed := NumPed

	Select CupomInt ; DbSetOrder(1)
	If DbSeek( pNumPed )
	
		pCodCxa := &dbftmp->CodCxa
		pNumCup := &dbftmp->NumPed

		cRet    := EnviaPagamentoXml( pCodCxa, pChvVal, pChvReq, pIdeInt, pSerPos, pCGCEMP, pVlrCup, pVlrCrt, "Pedido Caixa " + StrZero(pCodCxa,3) )

		If hb_At("|",cRet) > 0

			aToken  := hb_aTokens( cRet, "|" )		
			pIdFila := aToken[1]
			pPgtoLc := If( Upper(aToken[2])="SALVOEMARMAZENAMENTOLOCAL", "S", "N" )
			pIdRsFi := 0

			If pPgtoLc = "N"

				cRet := EnviaRespostaFiscalXml( pCodCxa, pChvVal, pIdFila, CupomInt->ChvCup, AllTrim(&dbftmp->NumNsu), AllTrim(&dbftmp->NumAut), AllTrim(&dbftmp->BanDei), AllTrim(&dbftmp->NomAdq), pCGCEMP, &dbftmp->NumCup )
				If hb_At("|",cRet) > 0
					aToken := hb_aTokens( cRet, "|" )
					If aToken[1] = "AP"
						pIdRsFi := Val(aToken[2])
					Endif		
				Endif

			Endif
			
			Select MeioPGint ; DbSetOrder(1)
			DbGoTop()
			OrdScope( 0, pNumCup )
			OrdScope( 1, pNumCup )
			DbGoTop()
			Do While !Eof()

				If Upper(AllTrim(MEIOPG)) == "CARTAO POS" .and. pSerPos == AllTrim(SerPos) .and. pVlrCup == TotPed .and. pVlrCrt = VlrPag 
					Trava()
					replace IdFila with pIdFila
					replace IDRSFI with pIdRsFi
					replace DatCon with Date()
					replace HorCon with Time()
					replace UsuCon with CODNOM
					ComitaOne()
				Endif

				DbSkip()

			Enddo

			OrdScope( 0, Nil )
			OrdScope( 1, Nil )
			
		Endif
	Endif
Endif

Close &dbftmp
Close MeioPGint
Close CupomInt

Return Nil
hb_out.txt

Código: Selecionar todos

Application Internal Error - C:\harbour32\sistemas\PafPDV\CriaSAT.exe
Terminated at: 2019-03-16 15:16:24
Erro irrecuper vel 9003: Muitas chamadas recursivas ao manipulador de erros
Called from DBUNLOCKALL(0)
Called from DEFERROR(223) in errorsysSAT.prg
Called from (b)ERRORSYS(22) in errorsysSAT.prg
Called from DBUNLOCKALL(0)
Called from DEFERROR(223) in errorsysSAT.prg
Called from (b)ERRORSYS(22) in errorsysSAT.prg
Called from DBUNLOCKALL(0)
Called from DEFERROR(223) in errorsysSAT.prg
Called from (b)ERRORSYS(22) in errorsysSAT.prg
Called from DBUNLOCKALL(0)
Called from DEFERROR(223) in errorsysSAT.prg
Called from (b)ERRORSYS(22) in errorsysSAT.prg
Called from DBUNLOCKALL(0)
Called from DEFERROR(223) in errorsysSAT.prg
Called from (b)ERRORSYS(22) in errorsysSAT.prg
Called from DBUNLOCKALL(0)
Called from DEFERROR(223) in errorsysSAT.prg
Called from (b)ERRORSYS(22) in errorsysSAT.prg
Called from DBUNLOCKALL(0)
Called from DEFERROR(223) in errorsysSAT.prg
Called from (b)ERRORSYS(22) in errorsysSAT.prg
Called from DBUNLOCKALL(0)
Called from DEFERROR(223) in errorsysSAT.prg
Called from (b)ERRORSYS(22) in errorsysSAT.prg
Called from DBUNLOCKALL(0)
Called from COMITA(12020) in funcoesSAT.prg
Called from SAIDAPDV(2549) in pdvSAT.prg
Called from (b)_PDVSAT(519) in pdvSAT.prg
Called from ENDDIALOG(834) in source\hdialog.prg
Called from (b)HDIALOG(96) in source\hdialog.prg
Called from HDIALOG:CLOSE(0) in source\hdialog.prg
Called from HDIALOG:ONEVENT(258) in source\hdialog.prg
Called from HWG_DLGBOXINDIRECT(0)
Called from HDIALOG:ACTIVATE(188) in source\hdialog.prg
Called from _PDVSAT(1035) in pdvSAT.prg
Called from PDVSAT(9) in pdvSAT.prg
Called from (b)_MAIN(770) in MenuSAT.prg
Called from HBUTTONEX:ONCLICK(1144) in source\hcontrol.prg
Called from (b)HBUTTON_NEW(1036) in source\hcontrol.prg
Called from DLGCOMMAND(568) in source\hdialog.prg
Called from (b)(_INITSTATICS00003)(0) in source\hdialog.prg
Called from HDIALOG:ONEVENT(255) in source\hdialog.prg
Called from SENDMESSAGE(0)
Called from HBUTTONEX:ONEVENT(1502) in source\hcontrol.prg
Called from HWG_DLGBOXINDIRECT(0)
Called from HDIALOG:ACTIVATE(188) in source\hdialog.prg
Called from _MAIN(828) in MenuSAT.prg
Called from MAIN(13) in MenuSAT.prg
------------------------------------------------------------------------
PS: Uso hwgui nesse projeto

Caixa preta de Thread

Enviado: 16 Mar 2019 16:39
por fladimir
Coloca um SLEEP no processo

Ou melhor coloca um semaforo...
Tipo assim

Código: Selecionar todos

			IF .NOT. FILE(cFileSemaforo) .OR. (FErase(cFileSemaforo) == 0)
				LogFileInfo(STRZERO(n,9) + ' Thread Ecommerce Consultando Pedidos '+ Dt2NmArq(Date()))
					nHandleNuvem := fCreate(cFileSemaforo) ; inkey(0.1) 
					FClose(nHandleNuvem)                   ; inkey(0.1) 
					nHandleNuvem := fOpen(cFileSemaforo, 1)  
					Mensag('Sincronizando com o site...', vcroxo) ; inkey(1)
					MP_Consulta(6, .F.)
					INKEY(1)
					Thread_Ecommerce_Aux_FiltraProdutos() // ve produtos ENVIA SITE
					FClose(nHandleNuvem) ; inkey(0.1) 
		  			FErase(cFileSemaforo) ; inkey(0.1) 
				LogFileInfo('Fim Rotina - Thread Ecommerce Consulta Pedidos')
			ELSE
				LogFileInfo(STRZERO(n,9) + ' Thread Ecommerce J  estava rodando ' + Dt2NmArq(Date()))
			ENDIF
			Limpa()
			LogFileInfo('Fim Rotina - Thread Ecommerce Consulta Pedidos')
		hb_idleSleep( nTempoEspera )

Caixa preta de Thread

Enviado: 16 Mar 2019 17:06
por janio
Na verdade a thread vai la e volta sem problema. Mas descobri aqui que quando volta o sistema fica doido SE na thread eu abrir uma tabela la. Se eu for na thread e voltar sem manipular tabelas, erros nao ocorrem ao voltar.

Como uso o Mediator, talvez esteja dando alguma B.O. la nesses casos.

Ta dificil
:(Neg

Caixa preta de Thread

Enviado: 16 Mar 2019 19:43
por fladimir
nas minhas threads manipulo tabelas mas usando o semafaro pra não ter recursividade, eu tinha exatamente esse erro q vc postou ai qdo não fazia isso.

Caixa preta de Thread

Enviado: 17 Mar 2019 08:48
por JoséQuintas
A coisa é simples: tá dando erro no seu fonte

A coisa complicou, quando a LIB não usou a rotina original do Harbour, e quis mostrar "erro bonitinho".
Está dando erro na rotina de erros, por isso fica em loop, porque a rotina de erros passa a chamar ela mesma pra tentar mostrar o erro dela mesma, e acaba NUNCA mostrando o verdadeiro erro - dá erro antes de mostrar o verdadeiro erro.

Opção 1: Veja se a LIB precisa algo mais pra indicar multithread.

Opção 2: Utilize minha rotina de erros, que funciona sempre - talvez precise mexer na LIB pra isso.

Caixa preta de Thread

Enviado: 17 Mar 2019 09:08
por janio
A coisa complicou, quando a LIB não usou a rotina original do Harbour, e quis mostrar "erro bonitinho".
Eh verdade, Quintas rsrsrs. Eu tenho aqui o meu proprio errorsys.prg q ficava chamando ela mesmo causando o erro recursivo.

Tirei o meu errorsys ele passou a mostrar o verdadeiro erro. Porem, descobri que realmente ha uma incompatilidade do Mediator com thread e que não tive tempo de aprofundar pra procurar esse erro. Se na thread eu nao chamar nenhum banco de dados (pelo mediator), ocorre tudo bem.

Como uso MySql e a rotina dessa thread precisa e ler e gravar dados, resolvi usando ADO e segui um tutorial que vc fez, Quintas. Showwwwww. Muito bom e ta tudo funcionando certinho agora.

Janio

Caixa preta de Thread

Enviado: 17 Mar 2019 09:11
por janio
nas minhas threads manipulo tabelas mas usando o semafaro pra não ter recursividade, eu tinha exatamente esse erro q vc postou ai qdo não fazia isso.
Fladimir, nesse meu caso eh uma incompatibilidade do Mediator com Thread. Não sei como, mas tem. Tentei tudo. Usar esses componentes externos eh muito bom, mas de vez em quando a gente pega uma dessas.

Janio

Caixa preta de Thread

Enviado: 17 Mar 2019 09:34
por Jairo Maia
janio escreveu:Se eu for na thread e voltar sem manipular tabelas, erros nao ocorrem ao voltar.
Jânio, sei que resolveu, mas não seria porque vc não está salvando o ambiente e retornando o ambiente anterior antes de voltar? Por exemplo:

Código: Selecionar todos

Function MinhaTHread()
Local GetList := {}, cOldAlias := Alias(), nOldIndice := IndexOrd(), nOldRec := RecN()

// Códigos

If !Empty( cOldAlias )
 Select( cOldAlias )
 DbSetOrder( nOldIndice )
 DbGoto( nOldRec )
EndIf

Return Nil

Caixa preta de Thread

Enviado: 17 Mar 2019 09:56
por janio
Jairo,

Pior que fiz tbm. Sem sucesso. Quando entra na thread e volta, qualquer manipulação de banco ocorre o erro anexo.

Como não tenho intimidade com thread, pensei que fosse algo relacionado, mas nao é. Basta dizer que abrindo dbf ou mesmo as tabelas mysql (usando ADO), não ocorre erro nenhum. Algo relacionado ao Mediator mesmo...

Resolvi com ADO e bola pra frente. Aliás, massa esse negocio de ADO. Ainda nao tinha usado e ja esta valendo pelo aprendizado.

Janio

Caixa preta de Thread

Enviado: 17 Mar 2019 14:21
por JoséQuintas
Jairo Maia escreveu:Jânio, sei que resolveu, mas não seria porque vc não está salvando o ambiente e retornando o ambiente anterior antes de voltar?
Multihread é igual EXE separado.
Se EXE separado não precisa salvar área anterior, , multithread também não.
Mas EXE separado precisaria inicializar Mediator nos dois EXEs, multithread também nas duas threads, se o Mediator deixar.

Caixa preta de Thread

Enviado: 17 Mar 2019 14:29
por JoséQuintas
JoséQuintas escreveu:Multihread é igual EXE separado.
Por falar nisso....
Como dois EXEs separados, fechar uma thread não fecha a outra.
Fechar o EXE não fecha threads, mas fecha arquivos e outras coisas mais.
Então, as threads rodando podem dar erro por faltar arquivo aberto, ao fechar o aplicativo.

É questão de costume, ou de montar um esquema de funcionamento de threads.

Se você tem um relatório sem tela, que abre pdf no final, pode fechar o aplicativo, e quando o relatório estiver pronto vai abrir o pdf, parecendo um fantasma... rs

Caixa preta de Thread

Enviado: 17 Mar 2019 16:41
por janio
Mas EXE separado precisaria inicializar Mediator nos dois EXEs, multithread também nas duas threads, se o Mediator deixar.
Hummmmm. Talvez o pulo do gato esteja aí: ao entrar na thread, fazer nova conexão com banco pelo mediator, assim como ja faço no início do sistema

Caixa preta de Thread

Enviado: 17 Mar 2019 19:11
por JoséQuintas
Pra passar variáveis entre threads, inclusive conexão, uso funções deste tipo:

Código: Selecionar todos

FUNCTION AppEmpresaApelido( xValue )

   STATIC AppEmpresaApelido := ""

   IF xValue != NIL
      AppEmpresaApelido := Trim( xValue )
   ENDIF

   RETURN AppEmpresaApelido

Código: Selecionar todos

AppEmpresaApelido( "nome" )
@ 1, 1 SAY SAY AppEmpresaApelido()
E aqui já usando minha classe, e passando a "variável" do ADO:

Código: Selecionar todos

   LOCAL cnMySql := ADOCLASS():New( AppcnMySqlLocal() )
Desse jeito uso a mesma conexão do ADO no aplicativo inteiro.
A classe é pra facilitar conversões, e outras coisas mais, mas a conexão é sempre a mesma (a não ser pra banco diferente).