Clipper On Line • Ver Tópico - Multi-Threads - Exemplo com Minigui

Multi-Threads - Exemplo com Minigui

Projeto MiniGui - Biblioteca visual para Harbour/xHarbour

Moderador: Moderadores

 

Multi-Threads - Exemplo com Minigui

Mensagempor yugi386 » 18 Ago 2013 00:15

Prezados amantes da Minigui (este exemplo se refere a minigui de Roberto Lopez),

Estive vendo como é simples utilizar threads com harbour. No entanto, quando fazia isto o formulário do sistema congelava e ás vezes até travava.
Aqui passo a estratégia que utilizei para sanar este problema. Neste exemplo a rotina principal apresenta uma barra de progresso enquanto duas
Threads geram o mapa do HD listando todos os arquivos da unidade C: e todos os arquivos da unidade D: em dois arquivos de texto.
Ao final de cada thread é apresentado o valor da variável inicio.

Primeiramente vamos ao código fonte do arquivo Main:

#include <hmg.ch>
#include "hbthread.ch"

memvar inicio // variavel acessivel dentro das threads
Function Main
        Load Window Main
        Main.Center
        Main.Activate
Return

function iniciar()
   inicio := 0
   
   // Veja como a simples a chamada das threads
   // Observe que as threads herdam os parametros da variavel memvar inicio
   nThreadId := hb_ThreadStart(  HB_THREAD_INHERIT_MEMVARS, @vthread() )
   nThreadId2 := hb_ThreadStart(  HB_THREAD_INHERIT_MEMVARS, @vthread2() )
           
   do while (inicio <= 100)
       Main.texto.value := str(inicio)
       Main.bar.value:= inicio
       Main.show()  // Necessário para dar o refresh na tela... é o pulo do gato...
       inicio = inicio + 2.5
       inkey(.5)
   enddo

   Main.bar.value:= 100
   msgbox("fim")
return

procedure vThread()
      for ct:= 1 to 1
         comando := "cmd /c dir c:\*.* /a/s > a.txt"
         run &comando
      next
      msgbox("fim da thread 1 " + str(inicio))
return NIL

procedure vThread2()
      comando := "cmd /c dir d:\*.* /a/s/on > b.txt"
      run &comando
      msgbox("fim da thread 2 " + str(inicio))
return NIL


Reparem na linha onde está Main.show(). Se você não colocar este comando a barra de progresso trava e somente é atualizada no final... Este é o pulo do gato!!!

O código fonte do formulário segue abaixo:

* HMG-IDE Form Designer Generated Code
* (c) Roberto Lopez - http://sites.google.com/site/hmgweb

DEFINE WINDOW TEMPLATE AT 196 , 331 WIDTH 550 HEIGHT 350 VIRTUAL WIDTH Nil VIRTUAL HEIGHT Nil TITLE "Exemplo de Thread em Harbour" ICON NIL MAIN CURSOR NIL ON INIT Nil ON RELEASE Nil ON INTERACTIVECLOSE Nil ON MOUSECLICK Nil ON MOUSEDRAG Nil ON MOUSEMOVE Nil ON SIZE Nil ON MAXIMIZE Nil ON MINIMIZE Nil ON PAINT Nil BACKCOLOR Nil NOTIFYICON NIL NOTIFYTOOLTIP NIL ON NOTIFYCLICK Nil ON GOTFOCUS Nil ON LOSTFOCUS Nil ON SCROLLUP Nil ON SCROLLDOWN Nil ON SCROLLLEFT Nil ON SCROLLRIGHT Nil ON HSCROLLBOX Nil ON VSCROLLBOX Nil

    DEFINE PROGRESSBAR Bar
        ROW    150
        COL    50
        WIDTH  450
        HEIGHT 60
        RANGEMIN 1
        RANGEMAX 100
        VALUE 0
        TOOLTIP ""
        HELPID Nil
        VISIBLE .T.
        SMOOTH .F.
        VERTICAL .F.
        BACKCOLOR NIL
        FORECOLOR NIL
    END PROGRESSBAR

    DEFINE BUTTON Button_1
        ROW    60
        COL    70
        WIDTH  100
        HEIGHT 28
        ACTION Iniciar()
        CAPTION "Iniciar"
        FONTNAME "Arial"
        FONTSIZE 9
        TOOLTIP ""
        FONTBOLD .F.
        FONTITALIC .F.
        FONTUNDERLINE .F.
        FONTSTRIKEOUT .F.
        ONGOTFOCUS Nil
        ONLOSTFOCUS Nil
        HELPID Nil
        FLAT .F.
        TABSTOP .T.
        VISIBLE .T.
        TRANSPARENT .F.
        MULTILINE .F.
        PICTURE Nil
        PICTALIGNMENT TOP
    END BUTTON

    DEFINE TEXTBOX texto
        ROW    70
        COL    320
        WIDTH  120
        HEIGHT 24
        FONTNAME "Arial"
        FONTSIZE 9
        TOOLTIP ""
        ONCHANGE Nil
        ONGOTFOCUS Nil
        ONLOSTFOCUS Nil
        FONTBOLD .F.
        FONTITALIC .F.
        FONTUNDERLINE .F.
        FONTSTRIKEOUT .F.
        ONENTER Nil
        HELPID Nil
        TABSTOP .T.
        VISIBLE .T.
        READONLY .F.
        RIGHTALIGN .F.
        DISABLEDBACKCOLOR Nil
        DISABLEDFONTCOLOR Nil
        BACKCOLOR NIL
        FONTCOLOR NIL
        INPUTMASK Nil
        FORMAT Nil
        VALUE ""
    END TEXTBOX

END WINDOW



Por padrão a minigui não compila o executável com a threads ativas. Para isto você deve habilitar este recurso na IDE, Gerenciador de Projeto, Aba configuração. Nesta aba configure o campo Multi-Thread para .T.

Saudações a todos!!
yugi386
Usuário Nível 2

Usuário Nível 2
 
Mensagens: 82
Data de registro: 24 Jul 2008 10:36
Cidade/Estado: Minas Gerais
Curtiu: 0 vez
Mens.Curtidas: 27 vezes

Multi-Threads - Exemplo com Minigui

Mensagempor Jairo Maia » 18 Ago 2013 04:56

Legal... Parabéns!

No meu caso o arquivo b.txt ficou vazio no primeiro teste, porque minha unidade D é o leitor de cd/dvd. Alterei pra F (meu slave) e listou também. Mostrou que seu exemplo funciona. Que venham outros...
Abraços, Jairo
Harbour / Clipper 5.2e - Blinker 7
(Não respondo dúvidas por MP ou E-mail. Por favor, não encaminhe via mensagem privada ou e-mail, dúvidas que podem ser compartilhadas com todos no fórum)
Avatar de usuário

Jairo Maia
Colaborador

Colaborador
 
Mensagens: 2733
Data de registro: 16 Ago 2010 13:46
Cidade/Estado: Campinas-SP
Curtiu: 371 vezes
Mens.Curtidas: 305 vezes

Multi-Threads - Exemplo com Minigui

Mensagempor yugi386 » 18 Ago 2013 13:33

Prezado Jairo,

Para dar mais uma contribuição neste sentido desenvolvi uma estratégia para rodar uma thread com um arquivo de lote ou programa externo sem apresentar a interface deste programa.
Isto é bom quando você precisa executar um arquivo de lote e não deseja que o usuário veja a tela do DOS ou interrompa o processo. O próprio arquivo de lote é criado dinamicamente então fica tudo um pouco mais seguro.

Vamos ao código: O exemplo da Thread é o mesmo do anterior, gerando dois mapas de arquivos de duas unidades do HD (C e D) neste caso. Se necessário basta alterar a unidade que o resultado será o mesmo.

#include <hmg.ch>
#include "hbthread.ch"

#define QUEBRA CHR(13) + CHR(10)  // quebra de linha

memvar inicio // variavel acessivel dentro das threads
Function Main
        Load Window Main
        Main.Center
        Main.Activate
Return

function iniciar()
   inicio := 0
   
   // Veja como a simples a chamada das threads
   // Observe que as threads herdam os parametros da variavel memvar inicio
   nThreadId := hb_ThreadStart(  HB_THREAD_INHERIT_MEMVARS, @vthread() )
   nThreadId2 := hb_ThreadStart(  HB_THREAD_INHERIT_MEMVARS, @vthread2() )
           
   do while (inicio <= 100)
       Main.texto.value := str(inicio)
       Main.bar.value:= inicio
       Main.show()  // Necessário para dar o refresh na tela...
       inicio = inicio + 2.5
       inkey(.5)
   enddo

   Main.bar.value:= 100
   msgbox("fim")
return

procedure vThread()
      comando := "dir c:\*.* /a/s > a.txt"
      memowrit("a.bat",comando)
      executaBatch("a.bat","a.vbs")
      msgbox("fim da thread 1 " + str(inicio))
return NIL

procedure vThread2()
      comando := "dir d:\*.* /a/s/on > b.txt"
      memowrit("b.bat",comando)
      executaBatch("b.bat","b.vbs")
      msgbox("fim da thread 2 " + str(inicio))
return NIL

* =======================================================================================
/**
  Executa um arquivo de lote ou programa silenciosamente sem mostrar a tela do DOS ou
  qualquer janela!!!
  Funciona somente no windows pois utiliza VBscript
*/
* ========================================================================================
procedure executaBatch(arquivoBAT,arquivoVBS)
   if file(arquivoVBS)
      delete file &arquivoVBS
   endif
   
   comando:= 'Set WshShell = WScript.CreateObject("WScript.Shell")' + QUEBRA +;
            'Dim statusCode' +  QUEBRA +;
            'Dim fso' +  QUEBRA +;           
            'statusCode = WshShell.Run ("' +arquivoBAT+ '", 0, true)'  + QUEBRA +;
            'Set fso = CreateObject("Scripting.FileSystemObject")'  + QUEBRA +;
            'fso.MoveFile ' + '"' + arquivoBAT + '"' + ',' + '"' + arquivoBAT + '.tmp"'

   memowrit(arquivoVBS,comando)
   EXECUTE FILE arquivoVBS // executando o script VBS
   
   // Rotina para fazer com que a execução do script seja completada
   // antes de terminar a thread
   
   arq := arquivoBAT + ".tmp"
   do while.t.
      if file(arq)
         delete file &arq
         exit
      endif
      inkey(0.5)
   enddo
   
   // excluindo script VBS
   comando :=  arquivoVBS
   delete file &comando
   
return



O pulo do gato neste caso é o uso de VBscript (neste caso só vai funcionar no windows). A procedure executaBatch(arquivoBAT,arquivoVBS) recebe dois parametros:

1. arquivoBAT = arquivo de lote a ser executado silenciosamente (pode ser um executável também).
2 arquivoVBS = indica o nome do script temporário vbs (ex: "a.vbs", você pode dar qualquer nome, contanto que tenha a extensão .vbs)

assim é possível executar muitas threads em background, de modo invisível para o usuário final.

O código completo do exemplo segue em anexo.

Saudações a todos,

Viva Harbour, Minigui e Clipper!!!!
Anexos
thread2.zip
Thread Invisível
(2.65 KiB) Baixado 244 vezes
yugi386
Usuário Nível 2

Usuário Nível 2
 
Mensagens: 82
Data de registro: 24 Jul 2008 10:36
Cidade/Estado: Minas Gerais
Curtiu: 0 vez
Mens.Curtidas: 27 vezes

Multi-Threads - Exemplo com Minigui

Mensagempor HASA » 19 Ago 2013 13:38

:)) :-O
Nossa, ai sim,
:{ :-Y
HASA
Avatar de usuário

HASA
Colaborador

Colaborador
 
Mensagens: 1082
Data de registro: 01 Set 2003 19:50
Cidade/Estado: São Paulo
Curtiu: 1 vez
Mens.Curtidas: 51 vezes

Multi-Threads - Exemplo com Minigui

Mensagempor Pablo César » 19 Ago 2013 16:16

Parabéns yugi !

Gostei do modo que resolveu a tela preta tanto indesejada !

Obrigado por compartilhar.
Um clip-abraço !

Pablo César Arrascaeta
Compartilhe suas dúvidas e soluções com todos os colegas aqui do fórum.
Evite enviar as dúvidas técnicas por MPs ou eMails, assim todos iremos beneficiar-nos.
Avatar de usuário

Pablo César
Usuário Nível 7

Usuário Nível 7
 
Mensagens: 5312
Data de registro: 31 Mai 2006 10:22
Cidade/Estado: Curitiba - Paraná
Curtiu: 142 vezes
Mens.Curtidas: 152 vezes

Multi-Threads - Exemplo com Minigui

Mensagempor HASA » 19 Ago 2013 16:54

:))
Olá Pablo, faz tempo que não vejo seus sempre prestativos post´s por aqui ( forum da Minigui ). Yugi, não sei se estou viajando no código fonte mas... em tese qualquer pequeno truque em VB poderiamos executar dessa forma ?, seria muito bom,
:%
HASA
Avatar de usuário

HASA
Colaborador

Colaborador
 
Mensagens: 1082
Data de registro: 01 Set 2003 19:50
Cidade/Estado: São Paulo
Curtiu: 1 vez
Mens.Curtidas: 51 vezes

Multi-Threads - Exemplo com Minigui

Mensagempor Jairo Maia » 20 Ago 2013 05:49

Olá Pessoal,

Fiquei na contra mão nesse exemplo. O exemplo funcionou, mas a tela do DOS aparece.

O efeito foi o mesmo substituindo o comando VBscript por: Hb_Run( "Start dir c:\*.* /a/s > a.txt" ) e Hb_Run( "Start dir F:\*.* /a/s/on > b.txt" ). Não consegui ver o resultado como foi proposto.

HMG.3.1.5 Unicode - Windows XP SP3 e no Seven. Em ambos casos o mesmo resultado.
Abraços, Jairo
Harbour / Clipper 5.2e - Blinker 7
(Não respondo dúvidas por MP ou E-mail. Por favor, não encaminhe via mensagem privada ou e-mail, dúvidas que podem ser compartilhadas com todos no fórum)
Avatar de usuário

Jairo Maia
Colaborador

Colaborador
 
Mensagens: 2733
Data de registro: 16 Ago 2010 13:46
Cidade/Estado: Campinas-SP
Curtiu: 371 vezes
Mens.Curtidas: 305 vezes

Multi-Threads - Exemplo com Minigui

Mensagempor yugi386 » 20 Ago 2013 06:52

Prezado Jairo,

No primeiro exemplo a tela do DOS aparece mesmo.
No segundo exemplo ela não aparece. Baixe o pacote thread2.zip, descompacte e execute como está.

Para que a tela do DOS não apareça você não pode executar o arquivo VBS através do comando RUN ou Hb_RUN, deverá executar com o comando EXECUTE FILE, conforme está no exemplo. Exatamente por isto é que não é possível rodar um arquivo bat diretamente sem que a tela do DOS apareça.

Ao executar um comando externo com RUN ou Hb_run será sempre aberta uma janela do CMD (interpretador de comandos) e é exatamente isto que não queremos.
Execute o VBscript sempre com EXECUTE FILE.

Aproveitando para responder o HASA, acredito que qualquer VBscript, em tese, possa ser executado desta forma sim. Não sou programador VB e apenas utilizei a característica do VBscript para nos auxiliar a ocultar as janelas do CMD.

abraço,

Yugi.
yugi386
Usuário Nível 2

Usuário Nível 2
 
Mensagens: 82
Data de registro: 24 Jul 2008 10:36
Cidade/Estado: Minas Gerais
Curtiu: 0 vez
Mens.Curtidas: 27 vezes

Multi-Threads - Exemplo com Minigui

Mensagempor asimoes » 26 Out 2013 08:52

Excelente contribuição,

Apenas ter cuidado se a aplicação abortar, porque o cmd fica executando o comando infinitamente e é preciso terminar a execução pelo gerenciador de tarefas.
â–º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 de usuário

asimoes
Colaborador

Colaborador
 
Mensagens: 4919
Data de registro: 26 Abr 2007 16:48
Cidade/Estado: RIO DE JANEIRO-RJ
Curtiu: 341 vezes
Mens.Curtidas: 258 vezes




Retornar para MiniGui

Quem está online

Usuários vendo este fórum: Nenhum usuário registrado online e 12 visitantes


Ola Amigo, espero que meu site e forum tem lhe beneficiado, com exemplos e dicas de programacao.
Entao divulgue o link da Doacao abaixo para seus amigos e redes sociais ou faça uma doacao para o site forum...
MUITO OBRIGADO PELA SUA DOACAO!
Faça uma doação para o forum
cron
v
Olá visitante, seja bem-vindo ao Fórum Clipper On Line!
Efetue o seu login ou faça o seu Registro