Publicidade

Neste artigo vou abordar um assunto muito polêmico: utilização de Threads no Visual Basic 6. Threads nada mais são que “tarefas”, ou seja, processos, funções, rotinas.

A técnica de Multithreading consiste em realizar tarefas simultaneamente, um conjunto de Threads trabalhando ao mesmo tempo. Todo sistema operacional multitarefa permite a utilização deste recurso (aliás, se não existisse multithreading não existiria Windows).

Para simplificar o entendimento, falamos de tarefas trabalhando “ao mesmo tempo”, porém sabemos que o processador não pode fazer duas coisas “ao mesmo tempo”. Existe todo um mecanismo por trás disso que permite que ele execute as tarefas aos poucos, ou seja, ao invés dele ficar dedicado a apenas uma rotina, ele executa um pouquinho de cada rotina, porém o intervalo de tempo em que ele faz isso é tão curto que para nós existe a impressão de que está fazendo “ao mesmo tempo”.

Um exemplo clássico de Multithreading seria a execução de dois laços infinitos ao mesmo tempo. Com a utilização de Threads você pode, por exemplo, realizar dois laços infinitos no seu programa e ainda assim poder clicar e utilizar controles enquanto isso.

Este recurso é muito útil na programação, porém o Visual Basic 6 apresenta um problema especial. Ele foi uma linguagem criada para trabalhar em STA (Single Threaded Apartment), o que significa que ele não permite execução concorrente.

Porém, utilizando algumas APIs do Windows podemos realizar este Multithreading, no entanto devido a essa restrição do VB6, este recurso se torna um pouco instável para tarefas muito prolongadas, mas para pequenas tarefas de pequenas durações podemos utilizá-lo sem problemas (porém ressalto que não é aconselhável, seria mais indicado o uso do VB.NET que já suporta este recurso totalmente).

Existem dois modos de realizar Multithreading no VB6:

Função: SHCreateThread

Apenas lança a execução de uma tarefa, recomendado para lançar caixas de mensagem MsgBox sem bloquear a execução. Imagine que chato se você tem um programa que monitora a entrada de dados pela porta paralela, então aparece um MsgBox com uma mensagem qualquer e o operador demora para apertar “OK”. Se seu programa lê a porta 10 vezes por segundo e o operador demorou 1 segundo para dar OK na simples e inofensiva MsgBox, seu programa perdeu 10 leituras da porta (dei o exemplo da porta, mas podemos citar também a chegada de dados por um Winsock por exemplo, onde um simples MsgBox acabaria com a confiabilidade do seu programa).

Esta técnica é usada da seguinte forma, você cria uma rotina pública num módulo com seu MsgBox:

No início do Módulo, a importação da DLL
Public Declare Function SHCreateThread Lib "shlwapi.dll" _

(ByVal pfnThreadProc As Long, pData As Any, ByVal dwFlags _

As Long, ByVal pfnCallback As Long) As Long 

'Sua rotina de multitarefa

Public Sub MensagemAlerta()

  MsgBox "O sistema está ativo !", vbOkOnly, "Status do sistema..."

End Sub

No Form, para exibir a mensagem, digitamos:

‘É enviado o AddressOf do nome da sua rotina de multitarefa

SHCreateThread AddressOf MensagemAlerta, ByVal 0&, &H1, ByVal 0&

Deste modo garantimos que a rotina “MensagemAlerta” será executada em multitarefa com o resto do programa (o programa continuará processando enquanto a mensagem é exibida).

Função: CreateThread

Este método permite que criemos Threads com um pouco mais de controle, porém se executado pelo “Run” do ambiente de compilação, o VB irá travar. Apesar do exemplo que darei ser instável, veremos o caso dos laços infinitos (ou quase infinitos) simultâneos. Pode ser utilizado como exemplo base para ser adaptado a suas necessidades de projeto.

Num módulo, escreva as rotinas que deseja executar simultaneamente:

‘No início do Módulo, a importação da DLL


Declare Function CreateThread Lib "kernel32" (lpThreadAttributes As _

Any, ByVal dwStackSize As Long, ByVal lpStartAddress As Long, _

lpParameter As Any, ByVal dwCreationFlags As Long, lpThreadID As Long) As Long

Declare Function TerminateThread Lib "kernel32" (ByVal hThread As _

Long, ByVal dwExitCode As Long) As Long

Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long 

'Variáveis para servir de identificador (handle) para o Thread

Public hThread1 As Long, hThread1_ID As Long

Public hThread2 As Long, hThread2_ID As Long 

'Suas rotinas de multitarefa

Public Sub Tarefa1()

Dim i As Long

    Do While True

        Form1.botao1.Caption = i

        i = i + 1

        If i > 32000000 Then i = 0

    Loop

End Sub 

Public Sub Tarefa2()

Dim i As Long

    Do While True

        Form1.botao2.Caption = i

        i = i + 1

        If i > 32000000 Then i = 0

    Loop

End Sub

Neste exemplo acima, as rotinas contarão um número muito grande e mostrarão na propriedade “Caption” de dois “CommandButton” (botao1, botao2) presentes no “Form1”

No Form, para executar as rotinas digitamos:
Private Sub Inicia_Click()

'Inicia a rotina "Tarefa1" em multitarefa

hThread1 = CreateThread(ByVal 0&, ByVal 0&, AddressOf Tarefa1, _

ByVal 0&, ByVal 0&, hThread1_ID) 

'Inicia a rotina "Tarefa2" em multitarefa

hThread2 = CreateThread(ByVal 0&, ByVal 0&, AddressOf Tarefa2, _

ByVal 0&, ByVal 0&, hThread2_ID) 

End Sub 

Private Sub Finaliza_Click()

'Finaliza a execução dos Threads 

TerminateThread hThread1, 0

TerminateThread hThread2, 0

CloseHandle hThread1

CloseHandle hThread2 

End Sub

Além dos botões que exibirão os contadores, teremos os botões “Inicia” e “Finaliza”. Lembre-se de compilar o programa e rodar pelo arquivo executável, pois no “Run” irá travar.

Venho enfatizar que utilizar multitarefa no Visual Basic 6 não é recomendado pelos autores, mas não quer dizer que é impossível de ser feito. Como vimos acima, é possível e muito útil para alguns casos.

Até o próximo artigo!