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!