Página 1 de 2

Multi thread, XHarbour 1.0.0 Console

Enviado: 18 Jan 2008 18:39
por Eolo
Srs.,

Decidi usar a função startthread() para, em determinados casos, fazer meu programa enviar do cliente para mim, em background, um email com algumas informações que me interessam, usando uma função de envio/recebimento de emails do padrinho Leonardo Sygecom. E isso funciona 100%.

O usuário nem percebe que o programa está trabalhando simultaneamente (na surdina) em outra coisa... Chic.

Pra isso, basta eu indicar, no HBMAKE, que vou "usar biblioteca multi thread".



Agora, a encrenca: entre as tais informações que me interessam, estão incluidos alguns arquivos, os quais eu desejo zipar usando a hb_zipfile() e anexar ao email... Em outras palavras, quero usar o THREAD junto com o ZIPFILE.

(ah, deixando o THREAD de lado: a função de envio de emails aceita normalmente mandar arquivos em anexo. Funciona perfeito.)


O que acontece:

a) se eu rodo o HBMAKE SEM a opção "usar a biblioteca multi thread" e aponto para a HBZIP.LIB, compila normal e roda normal, a ZIPagem é feita sem erro. Mas a THREAD não funciona, óbvio.

b) se eu faço a mesma coisa e MARCO a opção "usar a multi thread" (para que a função startthread() rode), nem compila, dá o seguinte erro: "Error: Unresolved external '_errno' reference from c:\xharbour\lib\hbzip.lib|zipfile'.

Aí, imaginando que a ZIP.LIB não funcione em MT, tentamos (eu e o Leo) usar uma DLL...

c) agora, com a opção "usar a multi thread" marcada e apontando para a nova HBZIPDLL.LIB, compila normal mas, quando rodo o EXE, ele ABORTA, exatamente quando chama a função da ZIPagem... Operação ilegal...


Bão, sou novato em XHarbour, nem sei se consegui explicar direito a encrenca. Alguém aí dá uma luz?

Ah:
a) tentei em vários PCs, com XP, 98 e ME. Mesmo resultado em todos...
b) tentei usar a backgroundrun(), mas não acertei... O segundo processamento não ocorre efetivamente em background! Só volta ao primeiro depois que o segundo termina. Talvez eu tenha feito algo errado.
c) um tár de MUTEX tem algo a ver com essa encrenca?

Enviado: 18 Jan 2008 19:18
por Maligno
MUTEX é, a grosso modo, um instrumento de controle de semáforos para aplicação em threads, ou mesmo de aplicações. Ou seja, pode ter utilidade (não relacionado ao erro em si), dependendo de como foi criada a lógica para ZIPar e enviar o eMail. Se há, por exemplo, uma thread para criar o ZIP e outra para enviar o eMail, é claro que um semáforo será necessário.

Agora, quanto ao erro em si, esse tal "Error: Unresolved external" é típico de símbolo não referenciado no script de linkedição. Isso é universal, independente de linguagem. Parece estar faltando biblioteca aí.

Enviado: 18 Jan 2008 20:07
por Eolo
Se há, por exemplo, uma thread para criar o ZIP e outra para enviar o eMail, é claro que um semáforo será necessário.
Como eu disse, é um thread só. Depois do ZIP pronto, eu tento mandar o email em background, via thread.

Repetindo, com outras palavras: o ZIP e o EMAIL/Thread funcinam 100%, quando isolados. Misturou, dá pau.
Agora, quanto ao erro em si, esse tal "Error: Unresolved external" é típico de símbolo não referenciado no script de linkedição. Isso é universal, independente de linguagem. Parece estar faltando biblioteca aí.
Releia o meu post.

Os itens A, B e C estão numa seqüência... Do item A pro B, a mesma LIB (que funciona no A) continua lá, mas não compila nem linka porque eu marquei o "usar biblioteca multi thread". Do item B pro C, mudei de LIB, compila normal (não há NADA unresolved), compila, linka, mas dá erro de runtime.

Então, não é FALTA de LIB. Talvez seja FALTA de LIBs compatíveis... Talvez alguém saiba dizer se é porque a LIB pra modo "não-MultiTarefa" não funciona em modo "MT"...

Enviado: 18 Jan 2008 20:57
por Maligno
Então, recapitulando...
b) se eu faço a mesma coisa e MARCO a opção "usar a multi thread" (para que a função startthread() rode), nem compila, dá o seguinte erro: "Error: Unresolved external '_errno' reference from c:\xharbour\lib\hbzip.lib|zipfile'.
Se separados tudo funciona bem, mas juntos não, posso deduzir que a biblioteca relacionada à MT pode conter um objeto de mesmo nome, integrante de HBZIP. Se a biblioteca de MT, no script de linkedição, é relacionada ANTES da HBZIP, será este objeto (sem o símbolo _errno) o linkado. Daí o erro. Uma tentativa de mudar isso, sem garantia de sucesso, seria trocar essas LIBs de lugar.
Aí, imaginando que a ZIP.LIB não funcione em MT, tentamos (eu e o Leo) usar uma DLL...

c) agora, com a opção "usar a multi thread" marcada e apontando para a nova HBZIPDLL.LIB, compila normal mas, quando rodo o EXE, ele ABORTA, exatamente quando chama a função da ZIPagem... Operação ilegal...
Qual a mensagem de erro? Você só falou de "operação ilegal".

Enviado: 19 Jan 2008 10:00
por Eolo
A tal operação "não legal" :-) é a seguinte:

Código: Selecionar todos

*** no Win98
CHEQUE3 causou uma falha de página inválida no
módulo HARBOUR.DLL em 0187:0063bbeb.
Registros:
EAX=00000001 CS=0187 EIP=0063bbeb EFLGS=00010202
EBX=00000400 SS=018f ESP=00a5f46c EBP=00a5f474
ECX=007eb53c DS=018f ESI=004b4fc4 FS=424f
EDX=00000000 ES=018f EDI=00000000 GS=0000
Bytes em CS:EIP:
8b 12 66 81 7a 0e ff 00 73 0b 8b 51 28 8b 12 0f 
Esvaziamento da pilha:
004b4fc4 00505908 00a5f5d8 005a52e0 00000001 00000400 00434759 00a5f490 0055d938 3a48543a 52413a31 50495a51 00430000 00a5f4a8 00505758 3a48543a

Enviado: 19 Jan 2008 10:29
por Maligno
Se fosse Clipper/BLinker até dava pra ver o mapa. Mas no XHarbour acredito que este recurso não existe.

Enviado: 19 Jan 2008 14:50
por Eolo
Se fosse Clipper tava no fórum do Clipper... :-)

Bão, vamos ver se aparece alguém que já tenha passado pelo problema ou tenha alguma idéia segura do que tá acontecendo. A mim me parece que as duas LIBs (ZIP e Email) estão "se estranhando", tipo a ZIP não foi feita pra rodar em MT...

Enviado: 19 Jan 2008 17:03
por Luciano Bonfim
Amigo

Já tentou mudar a ordem que essas libs aparecem no seu script, por exemplo quando comecei a usar a lib HWGUI penei pra descobrir que tenho que referenciá-la antes da What32 senäo näo rodava de jeito nenhum. bastou eu inverter a ordem que elas apareciam no script que funcionou

inverte pra ver se funciona

Boa Sorte

Enviado: 19 Jan 2008 18:30
por Eolo
Luciano, já tentei sim. E não resolveu.

Sou iniciante em HX, mas não em tudo, e isso de trocar LIBs de posição faz parte do "básico", que eu obviamente fiz antes de criar o tópico...

Enviado: 20 Jan 2008 11:50
por Luciano Bonfim
no meu caso esse "básico" que eu nao sabia me fez perder uns... 3 dias... rsrsrsrs

Enviado: 20 Jan 2008 18:06
por Eolo
Bem, finalmente achei uma solução que talvez não seja a melhor tecnicamente, mas que funciona: a função HB_OpenProcess() - que é algo como o RUN...

O processo PARENT ("pai"), que é o EXE principal sendo rodado, chama um outro EXE como CHILD ("filho"), e é o EXE Filho que envia o email, em background, sem abrir uma segunda janela. Com isso, o envio do email pode demorar o tempo que for preciso: o EXE Pai continua a execução normal, como se não houvesse o EXE Filho rodando... Nem dá pra perceber.

E dá pra trocar informações entre os dois processos! Eu não precisei usar isto, pois neste meu caso específico eu consegui manter os dois processos independentes, mas é possível passar parâmetros do Pai pro Filho e ler retornos do Filho pro Pai...


Complementando: esta função pode ser muito útil, por exemplo, no caso de um relatório muito extenso: o usuário escolhe lá as opções e, ao invés de ficar esperando o EXE Pai processar o relatório, ele pode ir fazer outra coisa, já que o EXE Filho é quem vai ficar processamento o relatório, em background...

Enviado: 21 Jan 2008 03:26
por sygecom
Eolo, faça o seguinte teste ai ! eu fiz aqui e deu certo...
Não link em seu Script nem a HBZIP e nem a HBZIPDLL depois pegue a DLL que vc gerou da HBZIP(através do BAT "dll_b32.bat" da pasta CONTRIB\HBZIP) e coloque na pasta do seu sistema, e use conforme abaixo:

Código: Selecionar todos

Function Teste
hDll := LoadLibrary( "hbzipdll.dll" )  // carrega a DLL para usar
vNome_zip := "LEO.zip"                 // nome do arq. ZIP
aArq:={"AGENDA.DBF"}                   // arquivo a ser Zipado
HB_LibDo("hb_zipfile","vNome_zip,aARQ, 9, ,.t., "SENHA",.F.,.F.,") // campacta
LibFree( hDll )                        // libera a DLL

StartThread( @Envia_Email(),vNome_zip)
....
....
....
Return
Abraços
Leonardo Machado

Enviado: 22 Jan 2008 16:12
por Eolo
Leonardo,

Vou anotar e examinar a sua sugestão mas, como falamos, não vai ajudar muito, pq no meu caso é preciso um EXE a mais e, no seu, uma DLL a mais. Então...

Bão, dei uma melhorada no meu EMAIL.exe e, agora, ele ficou "genérico" e mais fácil de usar: o EXE "parent" passa todas as informações pra ele (desde conta e senha até anexos, assunto etc e tals), via os argumentos da HB_OpenProcess(), e ele só bota o trem no correio, de acordo com as conformidades!

Enviado: 18 Fev 2008 12:03
por janio
Eolo escreveu: Complementando: esta função pode ser muito útil, por exemplo, no caso de um relatório muito extenso: o usuário escolhe lá as opções e, ao invés de ficar esperando o EXE Pai processar o relatório, ele pode ir fazer outra coisa, já que o EXE Filho é quem vai ficar processamento o relatório, em background...
Grande Eolo,

Estou precisando exatamente desse negócio para ir exibindo um relatório em TXT antes de este estar concluso.

Vc pode passar o caminho das pedras??

Jânio

Enviado: 19 Fev 2008 10:05
por Eolo
Jânio, desculpe não responder antes, é que to meio na correria...

Seguinte: eu usei a OpenProcess porque a Startthread - que usa Multi Thread - não tava se entendendo com a ZIP.LIB, dava pau na compilação. Mas aí o Leonardo Sygecom entrou na jogada e matou a charada: retificou e me mandou uma nova LIB.

Bem, eu ainda não tive tempo de mudar (continuo usando a OpenProcess), mas me parece que a Thread é melhor, tem mais opções para controlar o que está sendo feito "por baixo do pano"... E eu vou passar pra ela! Mas, por enquanto, respondendo à sua pergunta, aqui vai um exemplo (resumido) de como eu uso a OpenProcess:

Código: Selecionar todos

* Programa PAI.exe
function main()
* parâmetro a enviar para FILHO.exe
arg=pad("Cliente"+codi+ctod(date()),100)
* incia execução do segundo EXE...
alca:=hb_openprocess(FILHO.exe,@nstdin,@nstdout,@nstderr)
if alca>0
  * envia parâmetro para FILHO.exe
  fwrite(nstdin,arg)
endi

Nota: nstdIN manda info pro FILHO (como acima), nstdOUT recebe e nstdERR checa se deu pau. Eu só uso a primeira...

*... continua a execução normal do PAI.exe

* na saída:
if !type("ALCA")=="U"
  * se processo FILHO.exe foi iniciado...
  if alca>0
    * encerra FILHO.exe
    hb_closeprocess(alca,.f.)
  endi
endi

Código: Selecionar todos

* Programa FILHO.exe
function main()
#define fh_stdin  0
#define fh_stdout 1
#define fh_stderr 2
#include "fileio.ch"
priv linha
* pega parâmetro enviado pelo PAI.exe
linha=space(100)
fread(fh_stdin,@linha,len(linha))
* executa o que quiser em background...
* blablabla