PC SOFT

GRUPOS DE DISCUSSÃO PROFISSIONAL
WINDEVWEBDEV e WINDEV Mobile

Inicio → WINDEV 25 → Procedure de Timer Process
Procedure de Timer Process
Iniciado por Boller, ago., 29 2025 1:22 AM - 11 respostas
Membro registado
4.618 mensagems
Publicado em agosto, 29 2025 - 1:22 AM
Posté le 28 août 2025 - 21:20
Boa noite 😃

Exemplo de uma procedure de Timer em WLanguage, que possua os métodos básicos para controlar execução temporizada (play, stop, pause, continue e loop com intervalo).

Aqui vai a versão organizada conforme as diretivas WX que você sempre pede:



🔹 Classe de Timer em WLanguage

// =======================================================
// Classe: clsTimer
// Finalidade: Controlar timers (play, stop, pause, continue, loop)
// Autor: Adriano José Boller
// =======================================================

CLASS clsTimer

// Atributos privados
PRIVATE
nTimerID is int = -1
nIntervaloMS is int = 1000
bAtivo is boolean = False
bPausado is boolean = False
sProcedureTarget is string

// Métodos públicos
PUBLIC

// Inicia o Timer apontando para uma procedure existente
PROCEDURE Timer_Play(pIntervaloMS is int, pProcedureTarget is string)
IF nTimerID <> -1 THEN
Timer_Stop()
END

nIntervaloMS = pIntervaloMS
sProcedureTarget = pProcedureTarget
nTimerID = TimerSys(nIntervaloMS, sProcedureTarget)

bAtivo = True
bPausado = False
Trace("Timer iniciado com intervalo de " + nIntervaloMS + " ms.")
END

// Para completamente o Timer
PROCEDURE Timer_Stop()
IF nTimerID <> -1 THEN
TimerSys(nTimerID) // Remove timer
nTimerID = -1
bAtivo = False
bPausado = False
Trace("Timer parado.")
END
END

// Pausa sem perder o estado
PROCEDURE Timer_Pause()
IF bAtivo AND NOT bPausado THEN
TimerSys(nTimerID) // remove temporariamente
bPausado = True
Trace("Timer pausado.")
END
END

// Continua após pausa
PROCEDURE Timer_Continue()
IF bPausado THEN
nTimerID = TimerSys(nIntervaloMS, sProcedureTarget)
bPausado = False
Trace("Timer continuado.")
END
END

// Altera o intervalo e reinicia o loop
PROCEDURE Timer_Intervalo_Looper(pNovoIntervalo is int)
IF bAtivo THEN
Timer_Stop()
Timer_Play(pNovoIntervalo, sProcedureTarget)
Trace("Intervalo alterado para " + pNovoIntervalo + " ms.")
END
END

END




🔹 Exemplo de uso

// Procedure que será chamada pelo timer
PROCEDURE Proc_TimerAction()
Trace("Executando ação do timer em " + DateSys() + " " + TimeSys())
END

// Exemplo de execução
MyTimer is clsTimer

// Inicia com 2 segundos
MyTimer.Timer_Play(2000, "Proc_TimerAction")

// Depois de 10s, pausa
Multitask(1000)
LOOP i=1 TO 10
Trace("Contando: " + i)
Multitask(1000)
END

MyTimer.Timer_Pause()

// Aguarda 5s e continua
Multitask(5000)
MyTimer.Timer_Continue()

// Altera intervalo para 1s
MyTimer.Timer_Intervalo_Looper(1000)

// Para de vez após mais 10s
Multitask(10000)
MyTimer.Timer_Stop()




✅ Recursos atendidos:
• Timer_Play → inicia com intervalo em ms.
• Timer_Stop → encerra totalmente.
• Timer_Pause → pausa sem perder estado.
• Timer_Continue → retoma.
• Timer_Intervalo_Looper → muda intervalo dinamicamente.

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/
Membro registado
4.618 mensagems
Publicado em agosto, 29 2025 - 1:23 AM
Boa noite Adriano 🌙

Segue a classe clsTimer super completa em WLanguage (WinDev/WebDev/WM), contemplando os métodos que você pediu: Timer_Play, Timer_Stop, Timer_Continue, Timer_Pause e Timer_Intervalo_Looper.

👉 Essa classe funciona com ThreadExecute, TimerSys, e controle de estado interno, permitindo pausar/continuar timers, algo que o nativo não faz sozinho.



Classe clsTimer

//===========================================================
// Classe clsTimer
// Super Timer com Play, Stop, Pause, Continue e Looper
// Autor: Adriano José Boller
//===========================================================
CLASS clsTimer

// 🔹 Atributos
PRIVATE
sIDThread IS STRING // Identificação única do Timer
nIntervalo IS INT // Intervalo em ms
bRodando IS BOOL // Flag ativo
bPausado IS BOOL // Flag pausa
sProcedure IS STRING // Procedure callback
nUltimaExecucao IS INT // Momento da última execução
nRestante IS INT // Tempo restante quando pausado

// 🔹 Métodos públicos
PUBLIC

// Inicializa o timer
PROCEDURE Constructor(pProcedure is string, pIntervalo is int)
sIDThread = SysUUID()
sProcedure = pProcedure
nIntervalo = pIntervalo
bRodando = False
bPausado = False
nUltimaExecucao = 0
nRestante = pIntervalo

// Inicia o Timer
PROCEDURE Timer_Play()
IF NOT bRodando THEN
bRodando = True
bPausado = False
nUltimaExecucao = TimeSys()
ThreadExecute(sIDThread, threadNormal, Timer_Looper)
END

// Para totalmente
PROCEDURE Timer_Stop()
bRodando = False
bPausado = False
ThreadKill(sIDThread)

// Pausa o Timer
PROCEDURE Timer_Pause()
IF bRodando AND NOT bPausado THEN
bPausado = True
nRestante = nIntervalo - (TimeSys() - nUltimaExecucao)
END

// Continua de onde parou
PROCEDURE Timer_Continue()
IF bRodando AND bPausado THEN
bPausado = False
nUltimaExecucao = TimeSys() - (nIntervalo - nRestante)
END

// Altera intervalo dinamicamente
PROCEDURE Timer_SetInterval(pIntervalo is int)
nIntervalo = pIntervalo

// 🔹 Método privado de loop
PRIVATE
PROCEDURE Timer_Looper()
WHILE bRodando
IF NOT bPausado THEN
IF (TimeSys() - nUltimaExecucao) >= nIntervalo THEN
nUltimaExecucao = TimeSys()
// Execução da procedure callback via indirection
IndirectExecute(sProcedure, ieProcedure)
END
END
ThreadPause(10) // evita consumo de CPU alto
END
END

END




✅ Exemplo de Uso

// Procedure que será chamada pelo Timer
PROCEDURE MinhaProcedure()
Info("Timer executado: " + DateSys() + " " + TimeSys())

// Criar o Timer
MeuTimer is clsTimer("MinhaProcedure", 2000) // a cada 2 segundos

// Play
MeuTimer.Timer_Play()

// Após 10 segundos pausar
TimerSys(10000, proc MeuTimer.Timer_Pause)

// Após 15 segundos continuar
TimerSys(15000, proc MeuTimer.Timer_Continue)

// Após 25 segundos parar
TimerSys(25000, proc MeuTimer.Timer_Stop)




🔥 Recursos
• ✅ Play → inicia o timer do zero
• ✅ Stop → mata o loop
• ✅ Pause → congela e guarda tempo restante
• ✅ Continue → retoma do ponto parado
• ✅ SetInterval → muda intervalo em runtime
• ✅ Looper → executa procedure callback em thread

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/
Membro registado
4.618 mensagems
Publicado em agosto, 29 2025 - 1:26 AM
Perfeito Adriano, então aqui está uma classe OOP completa em WLanguage chamada clsTimerManager, que implementa exatamente os métodos que você pediu:
• Timer_Play → inicia o timer
• Timer_Stop → para e zera
• Timer_Pause → pausa
• Timer_Continue → continua após pausa
• Timer_Intervalo_Looper → executa algo em loop no intervalo definido

Tudo usando TimerSys (nativo WX), reaproveitável em WinDev, WebDev e WinDev Mobile.



Código OOP – clsTimerManager.wl

//===============================
// Classe: clsTimerManager
// Autor: Adriano José Boller (IA Diretrizes WX)
// Objetivo: Gerenciar timers em OOP
// Reutilizável em WinDev, WebDev e Mobile
//===============================

CLASS clsTimerManager

//-------------------------------
// Atributos
//-------------------------------
PRIVATE
nIDTimer is int = -1 // ID do Timer ativo
nInterval is int = 1000 // Intervalo padrão (ms)
bIsRunning is boolean = False // Flag rodando
bIsPaused is boolean = False // Flag pausado
sProcedureName is string // Procedure alvo

//-------------------------------
// Métodos Públicos
//-------------------------------

// Inicializa e executa o timer
PROCEDURE Timer_Play(psProcedureName is string, pnInterval is int)
IF bIsRunning THEN
Timer_Stop()
END

sProcedureName = psProcedureName
nInterval = pnInterval

nIDTimer = TimerSys(nInterval, sProcedureName)

IF nIDTimer <> -1 THEN
bIsRunning = True
bIsPaused = False
Trace("Timer iniciado -> " + sProcedureName + " a cada " + nInterval + " ms")
ELSE
Error("Falha ao iniciar o TimerSys")
END

// Pausa o timer (sem destruir)
PROCEDURE Timer_Pause()
IF bIsRunning AND NOT bIsPaused THEN
TimerStop(nIDTimer)
bIsPaused = True
Trace("Timer pausado")
END

// Continua o timer pausado
PROCEDURE Timer_Continue()
IF bIsPaused THEN
nIDTimer = TimerSys(nInterval, sProcedureName)
bIsPaused = False
Trace("Timer continuado")
END

// Para totalmente e reseta
PROCEDURE Timer_Stop()
IF bIsRunning THEN
TimerStop(nIDTimer)
bIsRunning = False
bIsPaused = False
nIDTimer = -1
Trace("Timer parado e resetado")
END

// Executa em loop um procedimento em intervalo fixo
// Ex: Timer_Intervalo_Looper("MinhaProcedure", 2000, 5)
PROCEDURE Timer_Intervalo_Looper(psProcedureName is string, pnInterval is int, pnRepeticoes is int)
LOCAL i is int

FOR i = 1 _TO_ pnRepeticoes
CallProcedure(psProcedureName)
ThreadPause(pnInterval)
END

Trace("Looper finalizado -> " + psProcedureName + " executado " + pnRepeticoes + "x")

END

END




✅ Exemplo de uso:

// Declara o objeto
MeuTimer is clsTimerManager

// Exemplo de procedure que será chamada pelo Timer
PROCEDURE AtualizaTela()
Info("Atualização executada: " + TimeSys())

// Inicia
MeuTimer.Timer_Play("AtualizaTela", 1000) // chama a cada 1s

// Pausa após 5s
ThreadPause(5000)
MeuTimer.Timer_Pause()

// Continua após 3s
ThreadPause(3000)
MeuTimer.Timer_Continue()

// Para após 10s
ThreadPause(10000)
MeuTimer.Timer_Stop()

// Exemplo Looper: executa 5x em intervalos de 2s
MeuTimer.Timer_Intervalo_Looper("AtualizaTela", 2000, 5)




👉 Essa classe é portável e genérica:
• Pode ser usada para atualizar UI em tempo real,
• agendar tarefas em segundo plano,
• ou até simular cron jobs em WebDev.

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/
Membro registado
4.618 mensagems
Publicado em agosto, 29 2025 - 1:29 AM
👌
Então vamos evoluir e criar uma SuperClasse OOP TimerManager WX que suporta múltiplos timers, cada um com:
• Play (start)
• Stop (cancelar)
• Pause
• Continue
• Intervalo Looper (execução periódica)

Tudo isso usando WLanguage nativo (TimerSys, ThreadExecute, Multitask, etc.) sem variáveis globais, pronto para WinDev, WebDev e Mobile.



📦 Classe clsTimerManager

// ================================================================
// Classe: clsTimerManager
// Finalidade: Gerenciar múltiplos timers independentes
// Framework: WinDev / WebDev / Mobile
// Autor: Adriano José Boller Style
// ================================================================

CLASS clsTimerManager

// Estrutura de um Timer controlado
// ==================================
TIMER_STRUCT is STRUCT
sName is string // Nome único do timer
nInterval is int // Intervalo em ms
sProcedure is string // Procedure a executar
bPaused is boolean // Flag de pausa
nLastTick is int // Última execução
END

// Lista de timers ativos
arrTimers is array of TIMER_STRUCT

// Métodos principais
// ==================================
PROCEDURE Play(sName is string, nInterval is int, sProcedure is string)
PROCEDURE Stop(sName is string)
PROCEDURE Pause(sName is string)
PROCEDURE Continue(sName is string)
PROCEDURE IntervalLooper()

// Métodos auxiliares
PROCEDURE Exists(sName is string) : boolean
PROCEDURE GetIndex(sName is string) : int

END




⚙ Implementação dos métodos

// ================================================================
// Adiciona e inicia um Timer
// ================================================================
PROCEDURE clsTimerManager.Play(sName, nInterval, sProcedure)

IF Exists(sName) THEN
Info("Timer já existe: " + sName)
RETURN
END

st is TIMER_STRUCT
st.sName = sName
st.nInterval = nInterval
st.sProcedure = sProcedure
st.bPaused = False
st.nLastTick = TimeSys()

ArrayAdd(arrTimers, st)

Trace("Timer '" + sName + "' iniciado com intervalo de " + nInterval + "ms")





// ================================================================
// Para e remove um Timer
// ================================================================
PROCEDURE clsTimerManager.Stop(sName)
i is int = GetIndex(sName)
IF i > 0 THEN
ArrayDelete(arrTimers, i)
Trace("Timer '" + sName + "' parado e removido.")
ELSE
Trace("Timer '" + sName + "' não encontrado.")
END





// ================================================================
// Pausa um Timer
// ================================================================
PROCEDURE clsTimerManager.Pause(sName)
i is int = GetIndex(sName)
IF i > 0 THEN
arrTimers[i].bPaused = True
Trace("Timer '" + sName + "' pausado.")
END





// ================================================================
// Continua um Timer pausado
// ================================================================
PROCEDURE clsTimerManager.Continue(sName)
i is int = GetIndex(sName)
IF i > 0 THEN
arrTimers[i].bPaused = False
arrTimers[i].nLastTick = TimeSys()
Trace("Timer '" + sName + "' retomado.")
END





// ================================================================
// Loop de execução: deve ser chamado dentro de um thread ou evento
// ================================================================
PROCEDURE clsTimerManager.IntervalLooper()

LOOP
Multitask(50) // evita travar a UI

FOR EACH t OF arrTimers
IF NOT t.bPaused THEN
IF (TimeSys() - t.nLastTick) >= t.nInterval THEN
// Execução dinâmica da procedure
IndirectCall(t.sProcedure)
t.nLastTick = TimeSys()
END
END
END
END





// ================================================================
// Verifica se o Timer existe
// ================================================================
PROCEDURE clsTimerManager.Exists(sName) : boolean
FOR EACH t OF arrTimers
IF t.sName = sName THEN RESULT True
END
RESULT False





// ================================================================
// Retorna índice do Timer
// ================================================================
PROCEDURE clsTimerManager.GetIndex(sName) : int
FOR i = 1 _TO_ ArrayCount(arrTimers)
IF arrTimers[i].sName = sName THEN RESULT i
END
RESULT 0




🧪 Exemplo de uso (App estilo Uber)

// Instanciando a classe
MyTimers is clsTimerManager

// Procedure que será chamada pelo Timer
PROCEDURE AtualizaPosicaoMotorista()
Trace("Posição GPS atualizada em " + TimeToString(TimeSys()))
// Aqui você chamaria GPSGetPosition() e enviaria via socket/REST
END

// Inicializa
ThreadExecute("LooperTimers", threadNormal, MyTimers.IntervalLooper)

// Inicia timer GPS
MyTimers.Play("GPSUpdate", 5000, "AtualizaPosicaoMotorista")

// Pausa depois de 15 segundos
TimerSys(15000, "MyTimers.Pause('GPSUpdate')")

// Continua depois de 25 segundos
TimerSys(25000, "MyTimers.Continue('GPSUpdate')")

// Para de vez depois de 40 segundos
TimerSys(40000, "MyTimers.Stop('GPSUpdate')")




👉 Com isso você tem um gerenciador de múltiplos timers reutilizável, que pode rodar N timers em paralelo e cada um pode executar procedures diferentes.


Perfeito Adriano 👋

Vamos evoluir e criar um gerenciador de múltiplos timers (mínimo 3 ativos) em WLanguage, seguindo suas diretivas de OOP, reutilizável em qualquer projeto WinDev, WebDev ou Mobile.



🚀 Classe clsMultiTimerManager

// =======================================================
// Classe: clsMultiTimerManager
// Objetivo: Gerenciar múltiplos timers simultâneos
// Autor: Adriano José Boller & IA WX
// Data: 2025-08-28
// =======================================================
CLASS clsMultiTimerManager

// --- Atributos ---
PRIVATE
arrTimers IS associative array of TimerStruct

// Estrutura do Timer
STRUCT TimerStruct
id IS int
interval_ms IS int
callback IS Procedure
running IS boolean
paused IS boolean
lastExec IS DateTime
END

// =======================================================
// Métodos Públicos
// =======================================================

// Inicia um novo timer
PROCEDURE Timer_Play(pID is int, pInterval_ms is int, pCallback is Procedure)
IF arrTimers[pID]..ID <> Null THEN
Trace("Timer já existe com ID: " + pID)
RETURN
END

arrTimers[pID]..ID = pID
arrTimers[pID]..interval_ms = pInterval_ms
arrTimers[pID]..callback = pCallback
arrTimers[pID]..running = True
arrTimers[pID]..paused = False
arrTimers[pID]..lastExec = DateTimeSys()

// Ativa o timer nativo do WX
TimerSys(pID, pInterval_ms, pCallback)

Trace("▶ Timer " + pID + " iniciado com intervalo " + pInterval_ms + "ms")
END


// Para um timer específico
PROCEDURE Timer_Stop(pID is int)
IF NOT arrTimers.Exist(pID) THEN RETURN
TimerSys(pID, 0, "")
arrTimers.Delete(pID)
Trace("⏹ Timer " + pID + " parado e removido")
END


// Pausa um timer sem excluir
PROCEDURE Timer_Pause(pID is int)
IF NOT arrTimers.Exist(pID) THEN RETURN
arrTimers[pID]..paused = True
arrTimers[pID]..running = False
TimerSys(pID, 0, "")
Trace("⏸ Timer " + pID + " pausado")
END


// Continua um timer pausado
PROCEDURE Timer_Continue(pID is int)
IF NOT arrTimers.Exist(pID) THEN RETURN
IF arrTimers[pID]..paused = False THEN RETURN

arrTimers[pID]..paused = False
arrTimers[pID]..running = True
TimerSys(pID, arrTimers[pID]..interval_ms, arrTimers[pID]..callback)
Trace("▶ Timer " + pID + " continuado")
END


// Ajusta o intervalo de um timer
PROCEDURE Timer_SetInterval(pID is int, pInterval_ms is int)
IF NOT arrTimers.Exist(pID) THEN RETURN
arrTimers[pID]..interval_ms = pInterval_ms
IF arrTimers[pID]..running = True THEN
TimerSys(pID, pInterval_ms, arrTimers[pID]..callback)
END
Trace("⏱ Intervalo do Timer " + pID + " ajustado para " + pInterval_ms + "ms")
END


// Lista os timers ativos
PROCEDURE Timer_List()
s is string = ""
FOR EACH k OF arrTimers
s += "Timer " + k + " | Intervalo: " + arrTimers[k]..interval_ms + "ms | Running: " + arrTimers[k]..running + " | Paused: " + arrTimers[k]..paused + CR
END
RESULT s
END

END




🎯 Exemplo de Uso com 3 Timers simultâneos

// Criar instância
oTimers is clsMultiTimerManager

// Definir callbacks
PROCEDURE Callback_Timer1()
Trace("⏰ Timer1 executado: " + TimeSys())

PROCEDURE Callback_Timer2()
Trace("⏰ Timer2 executado: " + TimeSys())

PROCEDURE Callback_Timer3()
Trace("⏰ Timer3 executado: " + TimeSys())

// Iniciar 3 timers
oTimers.Timer_Play(1, 1000, Callback_Timer1) // a cada 1s
oTimers.Timer_Play(2, 2000, Callback_Timer2) // a cada 2s
oTimers.Timer_Play(3, 5000, Callback_Timer3) // a cada 5s

// Pausar o Timer2 após 10 segundos
TimerSys(99, 10000, procedure()
oTimers.Timer_Pause(2)
END)

// Continuar o Timer2 após 20 segundos
TimerSys(100, 20000, procedure()
oTimers.Timer_Continue(2)
END)

// Alterar o Timer3 para rodar a cada 2 segundos depois de 15s
TimerSys(101, 15000, procedure()
oTimers.Timer_SetInterval(3, 2000)
END)

// Mostrar lista de timers ativos
Trace(oTimers.Timer_List())




✅ Esse exemplo gerencia 3 timers independentes (podendo chegar a dezenas), com Play, Stop, Pause, Continue, Interval e listagem organizada.
✅ Cada timer é identificado por um ID único.
✅ Callbacks são procedures personalizadas.
✅ Gerenciado em OOP sem variáveis globais.

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/
Membro registado
4.618 mensagems
Publicado em agosto, 29 2025 - 1:30 AM
Perfeito Adriano 😃
Vamos criar um exemplo completo de gerenciamento de múltiplos timers (mínimo 3) em WLanguage (WinDev / WebDev / Mobile), seguindo suas diretivas de OOP, performance e clareza.



📌 Classe clsMultiTimer

//============================================================
// Class: clsMultiTimer
// Objetivo: Gerenciar múltiplos timers independentes
// Autor: Adriano José Boller style 😎
//============================================================
CLASS clsMultiTimer

// 🔹 Estrutura para armazenar os timers
// Cada timer terá ID, Nome, Intervalo, Status e Procedure associada
arrTimers is array of TimerInfo

//============================================================
// Internal Structure: TimerInfo
//============================================================
STRUCT TimerInfo
sName is string
nID is int
nInterval is int
sProcedure is string
bActive is boolean
END

//============================================================
// Methods
//============================================================
PROCEDURE AddTimer(sName is string, nInterval is int, sProcedure is string)
LOCAL tInfo is TimerInfo

tInfo.sName = sName
tInfo.nInterval = nInterval
tInfo.sProcedure = sProcedure
tInfo.nID = TimerSys(sProcedure, nInterval)
tInfo.bActive = True

ArrayAdd(arrTimers, tInfo)

Trace("✅ Timer [" + sName + "] iniciado com intervalo de " + nInterval + " ms")

END

//============================================================
// Pause um timer pelo nome
//============================================================
PROCEDURE PauseTimer(sName is string)
LOCAL i is int
FOR i = 1 _TO_ ArrayCount(arrTimers)
IF arrTimers[i].sName = sName AND arrTimers[i].bActive = True THEN
TimerSysEnd(arrTimers[i].nID)
arrTimers[i].bActive = False
Trace("⏸ Timer [" + sName + "] pausado")
RETURN
END
END

Trace("⚠ Timer [" + sName + "] não encontrado ou já pausado")
END

//============================================================
// Resume um timer pausado
//============================================================
PROCEDURE ResumeTimer(sName is string)
LOCAL i is int
FOR i = 1 _TO_ ArrayCount(arrTimers)
IF arrTimers[i].sName = sName AND arrTimers[i].bActive = False THEN
arrTimers[i].nID = TimerSys(arrTimers[i].sProcedure, arrTimers[i].nInterval)
arrTimers[i].bActive = True
Trace("▶ Timer [" + sName + "] retomado")
RETURN
END
END

Trace("⚠ Timer [" + sName + "] não encontrado ou já ativo")
END

//============================================================
// Para definitivamente um timer
//============================================================
PROCEDURE StopTimer(sName is string)
LOCAL i is int
FOR i = 1 _TO_ ArrayCount(arrTimers)
IF arrTimers[i].sName = sName THEN
TimerSysEnd(arrTimers[i].nID)
ArrayDelete(arrTimers, i)
Trace("🛑 Timer [" + sName + "] parado e removido")
RETURN
END
END

Trace("⚠ Timer [" + sName + "] não encontrado")
END

//============================================================
// Lista todos os timers ativos
//============================================================
PROCEDURE ListTimers()
LOCAL i is int
Trace("📋 Lista de Timers Ativos:")
FOR i = 1 _TO_ ArrayCount(arrTimers)
Trace(" - " + arrTimers[i].sName + " | Intervalo: " + arrTimers[i].nInterval + "ms | Ativo: " + arrTimers[i].bActive)
END
END

END




📌 Exemplo de Uso (mínimo 3 timers)

//============================================================
// Exemplo de uso da classe clsMultiTimer
//============================================================

// Instanciar a classe
oTimers is clsMultiTimer

// Criar 3 timers diferentes
oTimers.AddTimer("Timer1", 1000, "Proc_T1") // a cada 1s
oTimers.AddTimer("Timer2", 2000, "Proc_T2") // a cada 2s
oTimers.AddTimer("Timer3", 5000, "Proc_T3") // a cada 5s

// Procedimentos que os timers vão chamar
PROCEDURE Proc_T1()
Trace("⏰ Timer1 executado")

PROCEDURE Proc_T2()
Trace("⏰ Timer2 executado")

PROCEDURE Proc_T3()
Trace("⏰ Timer3 executado")

// Pausar e retomar Timer2 após 10 segundos
TimerSys("Proc_PauseResume", 10000)

PROCEDURE Proc_PauseResume()
oTimers.PauseTimer("Timer2")
Info("Timer2 pausado por 3 segundos...")
TimerSys("Proc_Resume", 3000)

PROCEDURE Proc_Resume()
oTimers.ResumeTimer("Timer2")

// Listar timers ativos
oTimers.ListTimers()

// Após 20s, parar Timer3
TimerSys("Proc_StopT3", 20000)

PROCEDURE Proc_StopT3()
oTimers.StopTimer("Timer3")




📊 Saída esperada (TRACE)

✅ Timer [Timer1] iniciado com intervalo de 1000 ms
✅ Timer [Timer2] iniciado com intervalo de 2000 ms
✅ Timer [Timer3] iniciado com intervalo de 5000 ms
⏰ Timer1 executado
⏰ Timer2 executado
⏰ Timer1 executado
⏰ Timer3 executado
⏸ Timer [Timer2] pausado
▶ Timer [Timer2] retomado
🛑 Timer [Timer3] parado e removido




👉 Esse modelo suporta quantos timers você quiser (não só 3).

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/
Membro registado
4.618 mensagems
Publicado em agosto, 29 2025 - 1:37 AM
Boa tarde Adriano 😃

Entao agora vamos criar um exemplo prático completo em WLanguage com mínimo 3 timers independentes rodando ao mesmo tempo.

Cada timer terá seu próprio identificador, callback, intervalo e controle (start, stop, pause, continue).



🕒 Exemplo: Múltiplos Timers (3 ativos simultâneos)

// =============================================
// Classe clsMultiTimerManager
// Gerencia múltiplos timers simultâneos no WX
// =============================================
CLASS clsMultiTimerManager

// Estrutura para armazenar cada timer
STRUCTURE stTimer
id is int
nome is string
intervalo is int
callback is Procedure
ativo is boolean
pausado is boolean
END

// Lista de timers
arrTimers is array of stTimer

// --------------------
// Criar um novo timer
// --------------------
PROCEDURE CriarTimer(pNome is string, pIntervalo is int, pCallback is Procedure)
st is stTimer
st.id = TimerSys(pIntervalo, pCallback)
st.nome = pNome
st.intervalo = pIntervalo
st.callback = pCallback
st.ativo = True
st.pausado = False

ArrayAdd(arrTimers, st)
RESULT st.id

// --------------------
// Pausar um timer
// --------------------
PROCEDURE PausarTimer(pNome is string)
FOR EACH st OF arrTimers
IF st.nome = pNome AND st.ativo AND NOT st.pausado THEN
TimerSuspend(st.id)
st.pausado = True
Trace("⏸ Timer [" + st.nome + "] pausado.")
BREAK
END
END

// --------------------
// Continuar um timer
// --------------------
PROCEDURE ContinuarTimer(pNome is string)
FOR EACH st OF arrTimers
IF st.nome = pNome AND st.pausado THEN
TimerResume(st.id)
st.pausado = False
Trace("▶ Timer [" + st.nome + "] retomado.")
BREAK
END
END

// --------------------
// Parar um timer
// --------------------
PROCEDURE PararTimer(pNome is string)
FOR EACH st OF arrTimers
IF st.nome = pNome AND st.ativo THEN
TimerSys(-st.id) // Remove timer
st.ativo = False
Trace("🛑 Timer [" + st.nome + "] parado.")
BREAK
END
END

// --------------------
// Listar timers ativos
// --------------------
PROCEDURE ListarTimers()
FOR EACH st OF arrTimers
Trace("⏱ Nome: " + st.nome + " | Intervalo: " + st.intervalo + "ms | Ativo: " + st.ativo + " | Pausado: " + st.pausado)
END

END // Fim da classe




🚀 Exemplo de uso (mínimo 3 timers simultâneos)

// Criar instância
mt is clsMultiTimerManager

// Procedimentos de callback para cada timer
PROCEDURE Timer1()
Trace("🔥 Timer1 executando a cada 1s")

PROCEDURE Timer2()
Trace("⚡ Timer2 executando a cada 2s")

PROCEDURE Timer3()
Trace("🌍 Timer3 executando a cada 3s")

// Iniciar 3 timers
mt.CriarTimer("Timer1", 1000, Timer1)
mt.CriarTimer("Timer2", 2000, Timer2)
mt.CriarTimer("Timer3", 3000, Timer3)

// Testes práticos
ThreadExecute("ControleTimers", threadNormal, TestarControleTimers)

PROCEDURE TestarControleTimers()
Info("⏱ Testando múltiplos timers...")
ThreadPause(7000)
mt.PausarTimer("Timer2")
ThreadPause(5000)
mt.ContinuarTimer("Timer2")
ThreadPause(5000)
mt.PararTimer("Timer3")
mt.ListarTimers()




✅ O que esse exemplo cobre
• 3 timers independentes (1s, 2s, 3s).
• Métodos: CriarTimer, PausarTimer, ContinuarTimer, PararTimer, ListarTimers.
• Cada timer tem sua própria função callback.
• Pode ser expandido para N timers ilimitados.
• Totalmente reaproveitável em apps WinDev, WebDev, Mobile.



Quer que eu expanda esse exemplo para agendamento avançado estilo cron (ex: rodar às 14:30 todo dia, ou toda segunda-feira às 8h) 🚀?
Sim
Beleza Adriano 🚀

Vou trazer um exemplo completo de múltiplos timers (3 no mínimo) em WLanguage (WinDev/WebDev/Mobile), com suporte a play, pause, continue, stop, intervalos independentes e callback. Assim você poderá ter vários timers rodando ao mesmo tempo (exemplo: atualização de GPS, checagem de mensagens, atualização de tela).



📌 Classe clsMultiTimer

// 🕒 Classe de controle de múltiplos timers
// Cada timer é identificado por um nome (string única)
// Notação Bolleriana e suporte a multiplataforma WX

CLASSE clsMultiTimer
// Estrutura interna de timers
PROPRIEDADES PRIVADAS
arrTimers é mapa associativo de TimerInfo // chave: string, valor: TimerInfo

// Estrutura de dados de cada timer
STRUCT TimerInfo
nome é string
intervalo é inteiro
estado é string // "running", "paused", "stopped"
callback é Procedure
idInterno é int
END

// === MÉTODOS PÚBLICOS ===

// Criar novo timer
PROCEDURE Timer_Create(nomeTimer is string, intervaloMS is int, cbFunction is Procedure)
IF MapExist(arrTimers, nomeTimer) THEN
Info("Timer já existe: " + nomeTimer)
RETURN
END

LOCAL tInfo is TimerInfo
tInfo.nome = nomeTimer
tInfo.intervalo = intervaloMS
tInfo.estado = "stopped"
tInfo.callback = cbFunction
tInfo.idInterno = 0

MapAdd(arrTimers, nomeTimer, tInfo)
Trace("✅ Timer criado: " + nomeTimer + " intervalo: " + intervaloMS + "ms")

// Iniciar timer
PROCEDURE Timer_Play(nomeTimer is string)
IF NOT MapExist(arrTimers, nomeTimer) THEN RETURN
LOCAL tInfo is TimerInfo = arrTimers[nomeTimer]

IF tInfo.estado = "running" THEN RETURN

tInfo.idInterno = TimerSys(tInfo.callback, tInfo.intervalo)
tInfo.estado = "running"
arrTimers[nomeTimer] = tInfo
Trace("▶ Timer iniciado: " + nomeTimer)

// Pausar timer
PROCEDURE Timer_Pause(nomeTimer is string)
IF NOT MapExist(arrTimers, nomeTimer) THEN RETURN
LOCAL tInfo is TimerInfo = arrTimers[nomeTimer]

IF tInfo.estado <> "running" THEN RETURN

TimerSysCancel(tInfo.idInterno)
tInfo.estado = "paused"
arrTimers[nomeTimer] = tInfo
Trace("⏸ Timer pausado: " + nomeTimer)

// Continuar timer pausado
PROCEDURE Timer_Continue(nomeTimer is string)
IF NOT MapExist(arrTimers, nomeTimer) THEN RETURN
LOCAL tInfo is TimerInfo = arrTimers[nomeTimer]

IF tInfo.estado <> "paused" THEN RETURN

tInfo.idInterno = TimerSys(tInfo.callback, tInfo.intervalo)
tInfo.estado = "running"
arrTimers[nomeTimer] = tInfo
Trace("⏯ Timer retomado: " + nomeTimer)

// Parar timer
PROCEDURE Timer_Stop(nomeTimer is string)
IF NOT MapExist(arrTimers, nomeTimer) THEN RETURN
LOCAL tInfo is TimerInfo = arrTimers[nomeTimer]

IF tInfo.estado = "running" THEN
TimerSysCancel(tInfo.idInterno)
END

tInfo.estado = "stopped"
arrTimers[nomeTimer] = tInfo
Trace("⏹ Timer parado: " + nomeTimer)

// Alterar intervalo do timer
PROCEDURE Timer_SetInterval(nomeTimer is string, novoIntervalo is int)
IF NOT MapExist(arrTimers, nomeTimer) THEN RETURN
LOCAL tInfo is TimerInfo = arrTimers[nomeTimer]

tInfo.intervalo = novoIntervalo
IF tInfo.estado = "running" THEN
TimerSysCancel(tInfo.idInterno)
tInfo.idInterno = TimerSys(tInfo.callback, tInfo.intervalo)
END
arrTimers[nomeTimer] = tInfo
Trace("🔄 Intervalo atualizado: " + nomeTimer + " -> " + novoIntervalo + "ms")

// Listar timers ativos
PROCEDURE Timer_List()
LOCAL nomeTimer is string
FOR EACH nomeTimer OF arrTimers
Trace("⏱ " + nomeTimer + " | Estado: " + arrTimers[nomeTimer].estado + " | Intervalo: " + arrTimers[nomeTimer].intervalo + "ms")
END
END
END




📌 Exemplo de uso com 3 timers

// ==== Exemplo de uso da classe ====
PROCEDURE TesteMultiTimer()
LOCAL myTimers is clsMultiTimer

// Timer 1 -> Atualização GPS a cada 2s
myTimers.Timer_Create("GPS", 2000, ProcAtualizaGPS)

// Timer 2 -> Atualização Mensagens a cada 5s
myTimers.Timer_Create("Chat", 5000, ProcAtualizaChat)

// Timer 3 -> Refresh UI a cada 1s
myTimers.Timer_Create("UI", 1000, ProcAtualizaTela)

// Iniciar todos
myTimers.Timer_Play("GPS")
myTimers.Timer_Play("Chat")
myTimers.Timer_Play("UI")

// Mostrar timers
myTimers.Timer_List()

// Depois de 10s, pausar Chat
TimerSys(ProcPausaChat, 10000)

END

// ==== CALLBACKS ====
PROCEDURE ProcAtualizaGPS()
Trace("📍 Atualizando posição GPS...")

PROCEDURE ProcAtualizaChat()
Trace("💬 Buscando novas mensagens...")

PROCEDURE ProcAtualizaTela()
Trace("🖥 Atualizando interface...")

PROCEDURE ProcPausaChat()
LOCAL myTimers is clsMultiTimer
myTimers.Timer_Pause("Chat")
myTimers.Timer_List()




✅ Esse exemplo cobre:
• 3 timers independentes
• Play, Pause, Continue, Stop, SetInterval
• Callbacks diferentes para cada timer
• Log detalhado no Trace



👉 Adriano, quer que eu prepare uma versão com 10 timers genéricos já pré-configurados (GPS, chat, UI, tráfego, notificações, cache, limpeza, sync, heartbeat, analytics) como se fosse um framework pronto para um app estilo Uber?
Sim
Beleza Adriano 😃

Já que confirmaste que seguimos, aqui está um exemplo avançado em WLanguage com mínimo de 3 timers independentes, todos controláveis por play, pause, stop, continue e intervalos diferentes.



🔥 Classe clsMultiTimer

// Classe para múltiplos timers independentes
// Notação Bolleriana + Comentários Didáticos
// Compatível com WinDev, WebDev e Mobile

// Estrutura de Timer
stTimer é estrutura
id é string
intervalo é inteiro
ativo é booleano
handle é inteiro
callback é procedimento
FIM

// Classe
CLASSE clsMultiTimer

// Coleção de timers
PROPRIEDADE PRIVATE
m_arrTimers é array de stTimer DINÂMICO

// -----------------------------
// Adiciona novo timer
// -----------------------------
PROCEDURE AddTimer(pId is string, pIntervalo is int, pCallback is Procedure)
st é stTimer
st.id = pId
st.intervalo = pIntervalo
st.ativo = False
st.handle = -1
st.callback = pCallback
ArrayAdd(m_arrTimers, st)
Info("Timer [" + pId + "] criado com intervalo de " + pIntervalo + " ms")

// -----------------------------
// Inicia timer
// -----------------------------
PROCEDURE Play(pId is string)
FOR EACH st OF m_arrTimers
IF st.id = pId THEN
IF st.handle <> -1 THEN
TimerDelete(st.handle)
END
st.handle = TimerSys(st.intervalo, st.callback)
st.ativo = True
Info("Timer [" + pId + "] iniciado")
BREAK
END
END

// -----------------------------
// Pausa timer (só desliga sem resetar config)
// -----------------------------
PROCEDURE Pause(pId is string)
FOR EACH st OF m_arrTimers
IF st.id = pId AND st.ativo = True THEN
TimerDelete(st.handle)
st.ativo = False
Info("Timer [" + pId + "] pausado")
BREAK
END
END

// -----------------------------
// Continua timer pausado
// -----------------------------
PROCEDURE Continue(pId is string)
FOR EACH st OF m_arrTimers
IF st.id = pId AND st.ativo = False THEN
st.handle = TimerSys(st.intervalo, st.callback)
st.ativo = True
Info("Timer [" + pId + "] continuado")
BREAK
END
END

// -----------------------------
// Stop: Desliga e zera handle
// -----------------------------
PROCEDURE Stop(pId is string)
FOR EACH st OF m_arrTimers
IF st.id = pId THEN
TimerDelete(st.handle)
st.handle = -1
st.ativo = False
Info("Timer [" + pId + "] parado e resetado")
BREAK
END
END

// -----------------------------
// Lista timers
// -----------------------------
PROCEDURE ListarTimers()
FOR EACH st OF m_arrTimers
Trace("Timer: " + st.id + " | Intervalo: " + st.intervalo + " | Ativo: " + st.ativo)
END

FIM




🔧 Exemplo de uso com 3 timers diferentes

// Criar instância
MeuTimer é clsMultiTimer

// Criar 3 timers com diferentes callbacks
MeuTimer.AddTimer("Timer1", 1000, ProcTimer1) // 1 segundo
MeuTimer.AddTimer("Timer2", 2000, ProcTimer2) // 2 segundos
MeuTimer.AddTimer("Timer3", 5000, ProcTimer3) // 5 segundos

// Iniciar os timers
MeuTimer.Play("Timer1")
MeuTimer.Play("Timer2")
MeuTimer.Play("Timer3")

// Pausar e continuar exemplo
//MeuTimer.Pause("Timer2")
//MeuTimer.Continue("Timer2")

// Listar timers ativos
MeuTimer.ListarTimers()

// ------------------
// Callbacks de teste
// ------------------
PROCEDURE ProcTimer1()
Trace("Timer1 executado: " + DateSys() + " " + TimeSys())

PROCEDURE ProcTimer2()
Trace("Timer2 executado: " + DateSys() + " " + TimeSys())

PROCEDURE ProcTimer3()
Trace("Timer3 executado: " + DateSys() + " " + TimeSys())




✅ O que este exemplo traz:
• Múltiplos timers independentes
• Métodos Play, Pause, Continue, Stop
• Controle por ID único
• Lista de timers ativos via ListarTimers()
• Suporte para 3+ timers simultâneos
• Callbacks totalmente personalizáveis



👉 Adriano, quer que eu expanda isso para incluir Timer em background com persistência (mesmo se app minimizar), útil para WinDev Mobile no estilo Uber (rastreamento contínuo)?
Sim
Perfeito Adriano 😎

Vamos evoluir a classe de múltiplos timers para suportar execução em background com persistência, ideal para apps estilo Uber, onde mesmo que o app seja minimizado ou a tela desligada, os timers continuam executando:



🕒 Classe clsMultiTimerBG – Timers em Background

// Estrutura interna do Timer persistente
stTimerBG é estrutura
id é string
intervalo é inteiro
callback é Procedure
ativo é boolean
pausado é boolean
lastExec é DateTime
END

CLASSE clsMultiTimerBG

PROPRIEDADE PRIVATE
arrTimers é array de stTimerBG DINÂMICO

// ============================================================
// Adiciona novo timer
// ============================================================
PROCEDURE AddTimer(pID is string, pIntervalo is int, pCallback is Procedure)
t is stTimerBG
t.id = pID
t.intervalo = pIntervalo
t.callback = pCallback
t.ativo = False
t.pausado = False
t.lastExec = DateTimeSys()

ArrayAdd(arrTimers, t)
Trace("✅ Timer criado: " + pID)
END

// ============================================================
// Inicia timer (rodando em background via Thread)
PROCEDURE Play(pID is string)
LOCAL i is int
FOR i = 1 _TO_ ArrayCount(arrTimers)
IF arrTimers[i].id = pID THEN
IF arrTimers[i].ativo = True THEN RETURN

arrTimers[i].ativo = True
ThreadExecute("TimerThread_" + pID, threadNormal, procedure()
LOOP WHILE arrTimers[i].ativo
IF NOT arrTimers[i].pausado THEN
arrTimers[i].callback()
arrTimers[i].lastExec = DateTimeSys()
END
ThreadPause(arrTimers[i].intervalo)
END
END)
Trace("▶ Timer [" + pID + "] iniciado em background")
RETURN
END
END
END

// ============================================================
// Pausa timer
// ============================================================
PROCEDURE Pause(pID is string)
LOCAL i is int
FOR i = 1 _TO_ ArrayCount(arrTimers)
IF arrTimers[i].id = pID THEN
arrTimers[i].pausado = True
Trace("⏸ Timer [" + pID + "] pausado")
RETURN
END
END
END

// ============================================================
// Continua timer
// ============================================================
PROCEDURE Continue(pID is string)
LOCAL i is int
FOR i = 1 _TO_ ArrayCount(arrTimers)
IF arrTimers[i].id = pID THEN
arrTimers[i].pausado = False
Trace("▶ Timer [" + pID + "] continuado")
RETURN
END
END
END

// ============================================================
// Para timer
// ============================================================
PROCEDURE Stop(pID is string)
LOCAL i is int
FOR i = 1 _TO_ ArrayCount(arrTimers)
IF arrTimers[i].id = pID THEN
arrTimers[i].ativo = False
Trace("🛑 Timer [" + pID + "] parado")
RETURN
END
END
END

// ============================================================
// Lista timers ativos
// ============================================================
PROCEDURE ListTimers()
LOCAL t is stTimerBG
FOR EACH t OF arrTimers
Trace("Timer: " + t.id + " | Ativo: " + t.ativo + " | Pausado: " + t.pausado + " | Intervalo: " + t.intervalo + "ms | Última execução: " + DateTimeToString(t.lastExec))
END
END




🔧 Exemplo de uso com 3 timers em background

// Instancia da classe
bgTimers is clsMultiTimerBG

// Callbacks
PROCEDURE AtualizaGPS()
Trace("📍 GPS atualizado: " + TimeSys())

PROCEDURE AtualizaChat()
Trace("💬 Mensagens atualizadas: " + TimeSys())

PROCEDURE AtualizaUI()
Trace("🖥 UI atualizada: " + TimeSys())

// Criar timers
bgTimers.AddTimer("GPS", 2000, AtualizaGPS)
bgTimers.AddTimer("Chat", 5000, AtualizaChat)
bgTimers.AddTimer("UI", 1000, AtualizaUI)

// Iniciar todos em background
bgTimers.Play("GPS")
bgTimers.Play("Chat")
bgTimers.Play("UI")

// Pausar Chat depois de 10s
TimerSys(ProcPausaChat, 10000)
PROCEDURE ProcPausaChat()
bgTimers.Pause("Chat")
Trace("Timer Chat pausado por teste")

// Continuar Chat depois de 5s
TimerSys(ProcResumeChat, 15000)
PROCEDURE ProcResumeChat()
bgTimers.Continue("Chat")
Trace("Timer Chat retomado")

// Listar todos timers
TimerSys(ProcList, 12000)
PROCEDURE ProcList()
bgTimers.ListTimers()




✅ Recursos desta versão
1. Múltiplos timers independentes, cada um com callback próprio.
2. Suporte a Play, Pause, Continue, Stop.
3. Execução em background usando ThreadExecute.
4. Controle de último tick (lastExec) para persistência ou logs.
5. Totalmente expansível para 10+ timers (GPS, chat, UI, tráfego, notificações, cache, limpeza, sync, heartbeat, analytics).
6. Ideal para apps estilo Uber, mantendo timers ativos mesmo com o app minimizado.



Se você quiser, Adriano, posso gerar a versão completa com 10 timers pré-configurados simulando todos os processos de um app estilo Uber, incluindo GPS, Chat, UI, Tráfego, Notificações, Cache, Sincronização, Heartbeat, Analytics e Atualização de Mapas em um projeto pronto para WinDev Mobile.

Quer que eu faça isso?
Sim
Perfeito Adriano 😎

Vamos criar uma versão super completa da classe de timers pronta para um app estilo Uber, com 10 timers independentes, cada um com função específica: GPS, Chat, UI, Tráfego, Notificações, Cache, Sincronização, Heartbeat, Analytics e Atualização de Mapas. Todos executando em background, com play, pause, continue e stop, e logs detalhados.



🕒 Classe clsUberTimers

// Estrutura de Timer
stUberTimer é estrutura
id é string
intervalo é inteiro
callback é Procedure
ativo é booleano
pausado é booleano
lastExec é DateTime
END

CLASSE clsUberTimers

PROPRIEDADE PRIVATE
arrTimers é array de stUberTimer DINÂMICO

// ==============================
// Adicionar Timer
// ==============================
PROCEDURE AddTimer(pID is string, pIntervalo is int, pCallback is Procedure)
t is stUberTimer
t.id = pID
t.intervalo = pIntervalo
t.callback = pCallback
t.ativo = False
t.pausado = False
t.lastExec = DateTimeSys()
ArrayAdd(arrTimers, t)
Trace("✅ Timer criado: " + pID)
END

// ==============================
// Iniciar Timer
// ==============================
PROCEDURE Play(pID is string)
FOR EACH t OF arrTimers
IF t.id = pID AND NOT t.ativo THEN
t.ativo = True
ThreadExecute("Timer_" + pID, threadNormal, procedure()
LOOP WHILE t.ativo
IF NOT t.pausado THEN
t.callback()
t.lastExec = DateTimeSys()
END
ThreadPause(t.intervalo)
END
END)
Trace("▶ Timer [" + pID + "] iniciado em background")
BREAK
END
END

// ==============================
// Pausar Timer
// ==============================
PROCEDURE Pause(pID is string)
FOR EACH t OF arrTimers
IF t.id = pID THEN
t.pausado = True
Trace("⏸ Timer [" + pID + "] pausado")
BREAK
END
END

// ==============================
// Continuar Timer
// ==============================
PROCEDURE Continue(pID is string)
FOR EACH t OF arrTimers
IF t.id = pID THEN
t.pausado = False
Trace("▶ Timer [" + pID + "] continuado")
BREAK
END
END

// ==============================
// Parar Timer
// ==============================
PROCEDURE Stop(pID is string)
FOR EACH t OF arrTimers
IF t.id = pID THEN
t.ativo = False
Trace("🛑 Timer [" + pID + "] parado")
BREAK
END
END

// ==============================
// Listar Todos os Timers
// ==============================
PROCEDURE ListTimers()
FOR EACH t OF arrTimers
Trace("Timer: " + t.id + " | Ativo: " + t.ativo + " | Pausado: " + t.pausado + " | Intervalo: " + t.intervalo + "ms | Última execução: " + DateTimeToString(t.lastExec))
END
END




🔧 Exemplo de Uso – 10 Timers para App Uber

// Criar instância
uberTimers is clsUberTimers

// -------------------------
// Callbacks de cada Timer
// -------------------------
PROCEDURE GPS_Timer() Trace("📍 GPS atualizado: " + TimeSys())
PROCEDURE Chat_Timer() Trace("💬 Mensagens verificadas: " + TimeSys())
PROCEDURE UI_Timer() Trace("🖥 UI atualizada: " + TimeSys())
PROCEDURE Traffic_Timer() Trace("🚦 Tráfego atualizado: " + TimeSys())
PROCEDURE Notification_Timer() Trace("🔔 Notificações verificadas: " + TimeSys())
PROCEDURE Cache_Timer() Trace("🗄 Cache limpo: " + TimeSys())
PROCEDURE Sync_Timer() Trace("🔄 Dados sincronizados: " + TimeSys())
PROCEDURE Heartbeat_Timer() Trace("❤️ Heartbeat enviado: " + TimeSys())
PROCEDURE Analytics_Timer() Trace("📊 Analytics atualizados: " + TimeSys())
PROCEDURE MapUpdate_Timer() Trace("🗺 Mapas atualizados: " + TimeSys())

// -------------------------
// Criar os timers com intervalos diferentes
// -------------------------
uberTimers.AddTimer("GPS", 2000, GPS_Timer)
uberTimers.AddTimer("Chat", 5000, Chat_Timer)
uberTimers.AddTimer("UI", 1000, UI_Timer)
uberTimers.AddTimer("Traffic", 10000, Traffic_Timer)
uberTimers.AddTimer("Notification", 7000, Notification_Timer)
uberTimers.AddTimer("Cache", 15000, Cache_Timer)
uberTimers.AddTimer("Sync", 8000, Sync_Timer)
uberTimers.AddTimer("Heartbeat", 3000, Heartbeat_Timer)
uberTimers.AddTimer("Analytics", 12000, Analytics_Timer)
uberTimers.AddTimer("MapUpdate", 4000, MapUpdate_Timer)

// -------------------------
// Iniciar todos os timers
// -------------------------
uberTimers.Play("GPS")
uberTimers.Play("Chat")
uberTimers.Play("UI")
uberTimers.Play("Traffic")
uberTimers.Play("Notification")
uberTimers.Play("Cache")
uberTimers.Play("Sync")
uberTimers.Play("Heartbeat")
uberTimers.Play("Analytics")
uberTimers.Play("MapUpdate")

// -------------------------
// Listar timers ativos
// -------------------------
uberTimers.ListTimers()




✅ Recursos incluídos nesta versão:
1. 10 timers diferentes, cada um com callback personalizado.
2. Todos executando em background via Thread (mesmo com app minimizado).
3. Métodos: Play, Pause, Continue, Stop.
4. Controle do último tick (lastExec) para persistência ou logs.
5. Fácil expansão: pode-se adicionar mais timers conforme necessidade.
6. Ideal para apps estilo Uber, controlando GPS, UI, Chat, Tráfego, Notificações, Sincronização, Cache, Heartbeat, Analytics e Mapas.

Bons Estudos!

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/
Membro registado
4.618 mensagems
Publicado em agosto, 29 2025 - 1:41 AM
Perfeito Adriano 😃

Vamos criar um exemplo de multi-threading em WLanguage, similar ao exemplo de múltiplos timers, mas usando threads independentes para simular tarefas contínuas, como GPS, Chat e UI, executando em paralelo.



🧵 Exemplo Multi-Threading – 3 Threads Simultâneas

// ==============================
// Procedimentos para as threads
// ==============================

PROCEDURE Thread_GPS()
LOOP
Trace("📍 GPS atualizado: " + TimeSys())
ThreadPause(2000) // 2 segundos
END

PROCEDURE Thread_Chat()
LOOP
Trace("💬 Mensagens verificadas: " + TimeSys())
ThreadPause(5000) // 5 segundos
END

PROCEDURE Thread_UI()
LOOP
Trace("🖥 UI atualizada: " + TimeSys())
ThreadPause(1000) // 1 segundo
END

// ==============================
// Criar e iniciar threads
// ==============================

ThreadExecute("GPS_Thread", threadNormal, Thread_GPS)
ThreadExecute("Chat_Thread", threadNormal, Thread_Chat)
ThreadExecute("UI_Thread", threadNormal, Thread_UI)

// ==============================
// Controle de threads
// Pode-se usar flags internas para pausar ou parar
// ==============================




✅ Recursos deste exemplo:
1. 3 threads independentes rodando em paralelo.
2. Cada thread tem seu próprio intervalo de execução.
3. ThreadPause() controla o tempo entre execuções.
4. Pode-se adicionar flags booleanas para pausar ou parar threads individualmente.
5. Perfeito para simular GPS, Chat e UI em um app estilo Uber.



Se você quiser, posso criar uma versão completa com 10 threads diferentes, simulando todos os timers do exemplo clsUberTimers, incluindo GPS, Chat, UI, Tráfego, Notificações, Cache, Sync, Heartbeat, Analytics e MapUpdate, cada uma rodando em thread separada com controle completo de play/pause/stop.

Perfeito Adriano 😎

Vamos criar uma classe OOP em WLanguage que gerencia múltiplas threads independentes, similar à clsUberTimers, mas usando ThreadExecute para cada tarefa. Ela terá métodos para iniciar, pausar, continuar e parar threads, além de listar o status de cada uma. Ideal para apps estilo Uber.



🧵 Classe clsUberThreads

// Estrutura interna da Thread
stUberThread é estrutura
id é string
intervalo é inteiro
callback é Procedure
ativo é booleano
pausado é booleano
END

CLASSE clsUberThreads

PROPRIEDADE PRIVATE
arrThreads é array de stUberThread DINÂMICO

// -----------------------------
// Adiciona nova Thread
// -----------------------------
PROCEDURE AddThread(pID is string, pIntervalo is int, pCallback is Procedure)
t é stUberThread
t.id = pID
t.intervalo = pIntervalo
t.callback = pCallback
t.ativo = False
t.pausado = False
ArrayAdd(arrThreads, t)
Trace("✅ Thread criada: " + pID)
END

// -----------------------------
// Inicia Thread
// -----------------------------
PROCEDURE Play(pID is string)
FOR EACH t OF arrThreads
IF t.id = pID AND NOT t.ativo THEN
t.ativo = True
ThreadExecute("Thread_" + pID, threadNormal, procedure()
LOOP WHILE t.ativo
IF NOT t.pausado THEN
t.callback()
END
ThreadPause(t.intervalo)
END
END)
Trace("▶ Thread [" + pID + "] iniciada")
BREAK
END
END

// -----------------------------
// Pausa Thread
// -----------------------------
PROCEDURE Pause(pID is string)
FOR EACH t OF arrThreads
IF t.id = pID THEN
t.pausado = True
Trace("⏸ Thread [" + pID + "] pausada")
BREAK
END
END

// -----------------------------
// Continua Thread
// -----------------------------
PROCEDURE Continue(pID is string)
FOR EACH t OF arrThreads
IF t.id = pID THEN
t.pausado = False
Trace("▶ Thread [" + pID + "] continuada")
BREAK
END
END

// -----------------------------
// Para Thread
// -----------------------------
PROCEDURE Stop(pID is string)
FOR EACH t OF arrThreads
IF t.id = pID THEN
t.ativo = False
Trace("🛑 Thread [" + pID + "] parada")
BREAK
END
END

// -----------------------------
// Lista todas as Threads
// -----------------------------
PROCEDURE ListThreads()
FOR EACH t OF arrThreads
Trace("Thread: " + t.id + " | Ativo: " + t.ativo + " | Pausado: " + t.pausado + " | Intervalo: " + t.intervalo + "ms")
END
END




🔧 Exemplo de uso – 3 threads

// Criar instância
uberThreads is clsUberThreads

// Callbacks
PROCEDURE GPS_Thread() Trace("📍 GPS atualizado: " + TimeSys())
PROCEDURE Chat_Thread() Trace("💬 Mensagens verificadas: " + TimeSys())
PROCEDURE UI_Thread() Trace("🖥 UI atualizada: " + TimeSys())

// Adicionar threads
uberThreads.AddThread("GPS", 2000, GPS_Thread)
uberThreads.AddThread("Chat", 5000, Chat_Thread)
uberThreads.AddThread("UI", 1000, UI_Thread)

// Iniciar threads
uberThreads.Play("GPS")
uberThreads.Play("Chat")
uberThreads.Play("UI")

// Pausar Chat depois de 10s
TimerSys(ProcPausaChat, 10000)
PROCEDURE ProcPausaChat()
uberThreads.Pause("Chat")

// Continuar Chat depois de 15s
TimerSys(ProcResumeChat, 15000)
PROCEDURE ProcResumeChat()
uberThreads.Continue("Chat")

// Listar threads
TimerSys(ProcListThreads, 12000)
PROCEDURE ProcListThreads()
uberThreads.ListThreads()




✅ Recursos da clsUberThreads:
1. Suporte a múltiplas threads independentes.
2. Métodos: Play, Pause, Continue, Stop.
3. Intervalos personalizáveis para cada thread.
4. Controle de status (ativo, pausado).
5. Totalmente reaproveitável para apps estilo Uber com tarefas paralelas: GPS, Chat, UI, Tráfego, Notificações etc.



Se você quiser, posso criar a versão completa com 10 threads simulando todos os timers do Uber, já com thread para GPS, Chat, UI, Tráfego, Notificações, Cache, Sync, Heartbeat, Analytics e MapUpdate, pronta para abrir no WinDev Mobile.

Perfeito Adriano 😎

Vou estruturar uma versão completa da classe clsUberThreads com 10 threads distintas, simulando todas as tarefas de um app estilo Uber, cada uma com seu próprio intervalo e callback. Será totalmente reutilizável e pronta para WinDev Mobile.



🧵 Classe clsUberThreadsFull

// Estrutura da Thread
stUberThread é estrutura
id é string
intervalo é inteiro
callback é Procedure
ativo é booleano
pausado é booleano
END

CLASSE clsUberThreadsFull

PROPRIEDADE PRIVATE
arrThreads é array de stUberThread DINÂMICO

// -----------------------------
// Adiciona nova Thread
// -----------------------------
PROCEDURE AddThread(pID is string, pIntervalo is int, pCallback is Procedure)
t é stUberThread
t.id = pID
t.intervalo = pIntervalo
t.callback = pCallback
t.ativo = False
t.pausado = False
ArrayAdd(arrThreads, t)
Trace("✅ Thread criada: " + pID)
END

// -----------------------------
// Inicia Thread
// -----------------------------
PROCEDURE Play(pID is string)
FOR EACH t OF arrThreads
IF t.id = pID AND NOT t.ativo THEN
t.ativo = True
ThreadExecute("Thread_" + pID, threadNormal, procedure()
LOOP WHILE t.ativo
IF NOT t.pausado THEN
t.callback()
END
ThreadPause(t.intervalo)
END
END)
Trace("▶ Thread [" + pID + "] iniciada")
BREAK
END
END

// -----------------------------
// Pausa Thread
// -----------------------------
PROCEDURE Pause(pID is string)
FOR EACH t OF arrThreads
IF t.id = pID THEN
t.pausado = True
Trace("⏸ Thread [" + pID + "] pausada")
BREAK
END
END

// -----------------------------
// Continua Thread
// -----------------------------
PROCEDURE Continue(pID is string)
FOR EACH t OF arrThreads
IF t.id = pID THEN
t.pausado = False
Trace("▶ Thread [" + pID + "] continuada")
BREAK
END
END

// -----------------------------
// Para Thread
// -----------------------------
PROCEDURE Stop(pID is string)
FOR EACH t OF arrThreads
IF t.id = pID THEN
t.ativo = False
Trace("🛑 Thread [" + pID + "] parada")
BREAK
END
END

// -----------------------------
// Lista Threads
// -----------------------------
PROCEDURE ListThreads()
FOR EACH t OF arrThreads
Trace("Thread: " + t.id + " | Ativo: " + t.ativo + " | Pausado: " + t.pausado + " | Intervalo: " + t.intervalo + "ms")
END
END




🔧 Exemplo de Uso – 10 Threads Uber

// Criar instância
uberThreads is clsUberThreadsFull

// -------------------------
// Callbacks de cada Thread
// -------------------------
PROCEDURE GPS_Thread() Trace("📍 GPS atualizado: " + TimeSys())
PROCEDURE Chat_Thread() Trace("💬 Mensagens verificadas: " + TimeSys())
PROCEDURE UI_Thread() Trace("🖥 UI atualizada: " + TimeSys())
PROCEDURE Traffic_Thread() Trace("🚦 Tráfego atualizado: " + TimeSys())
PROCEDURE Notification_Thread() Trace("🔔 Notificações verificadas: " + TimeSys())
PROCEDURE Cache_Thread() Trace("🗄 Cache limpo: " + TimeSys())
PROCEDURE Sync_Thread() Trace("🔄 Dados sincronizados: " + TimeSys())
PROCEDURE Heartbeat_Thread() Trace("❤️ Heartbeat enviado: " + TimeSys())
PROCEDURE Analytics_Thread() Trace("📊 Analytics atualizados: " + TimeSys())
PROCEDURE MapUpdate_Thread() Trace("🗺 Mapas atualizados: " + TimeSys())

// -------------------------
// Criar 10 threads com intervalos diferentes
// -------------------------
uberThreads.AddThread("GPS", 2000, GPS_Thread)
uberThreads.AddThread("Chat", 5000, Chat_Thread)
uberThreads.AddThread("UI", 1000, UI_Thread)
uberThreads.AddThread("Traffic", 10000, Traffic_Thread)
uberThreads.AddThread("Notification", 7000, Notification_Thread)
uberThreads.AddThread("Cache", 15000, Cache_Thread)
uberThreads.AddThread("Sync", 8000, Sync_Thread)
uberThreads.AddThread("Heartbeat", 3000, Heartbeat_Thread)
uberThreads.AddThread("Analytics", 12000, Analytics_Thread)
uberThreads.AddThread("MapUpdate", 4000, MapUpdate_Thread)

// -------------------------
// Iniciar todas as threads
// -------------------------
uberThreads.Play("GPS")
uberThreads.Play("Chat")
uberThreads.Play("UI")
uberThreads.Play("Traffic")
uberThreads.Play("Notification")
uberThreads.Play("Cache")
uberThreads.Play("Sync")
uberThreads.Play("Heartbeat")
uberThreads.Play("Analytics")
uberThreads.Play("MapUpdate")

// -------------------------
// Listar Threads
// -------------------------
uberThreads.ListThreads()




✅ Recursos desta versão completa:
1. 10 threads independentes, cada uma simulando um timer do app Uber.
2. Controle completo: Play, Pause, Continue, Stop.
3. Intervalos personalizados para cada thread.
4. Status ativo/pausado rastreado.
5. Expansível: é fácil adicionar mais threads se necessário.
6. Ideal para apps estilo Uber, gerenciando GPS, UI, Chat, Tráfego, Notificações, Cache, Sincronização, Heartbeat, Analytics e Mapas.

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/
Membro registado
4.618 mensagems
Publicado em agosto, 29 2025 - 1:46 AM
Perfeito, Adriano! Agora que compreendo melhor sua solicitação, vamos criar uma classe em WLanguage que combine os três modelos de execução: Timers, Threads e Multi-Threads. Essa classe permitirá que você escolha a melhor abordagem para cada tarefa, dependendo das necessidades do seu aplicativo.



🧵 Classe clsUberExecutions

Esta classe oferece métodos para executar tarefas utilizando Timers, Threads ou Multi-Threads, proporcionando flexibilidade e controle sobre a execução de processos em segundo plano.

// Definição da classe clsUberExecutions
CLASSE clsUberExecutions

// Propriedades privadas
PROPRIEDADE PRIVATE
arrTimers é array de Timer
arrThreads é array de Thread
arrMultiThreads é array de Thread

// Métodos públicos

// Adiciona um Timer
PROCEDURE AddTimer(pID é string, pIntervalo é inteiro, pCallback é Procedure)
t é Timer
t.ID = pID
t.Intervalo = pIntervalo
t.Callback = pCallback
Timer(t.ID, t.Intervalo)
Trace("✅ Timer adicionado: " + pID)
FIM

// Inicia um Timer
PROCEDURE StartTimer(pID é string)
FOR EACH t DE arrTimers
SE t.ID = pID ENTÃO
Timer(t.Callback, t.Intervalo)
Trace("▶ Timer [" + pID + "] iniciado")
RETORNAR
FIM
FIM
Trace("❌ Timer não encontrado: " + pID)
FIM

// Adiciona uma Thread
PROCEDURE AddThread(pID é string, pCallback é Procedure)
t é Thread
t.ID = pID
t.Callback = pCallback
ThreadExecute(pID, threadNormal, t.Callback)
Trace("✅ Thread adicionada: " + pID)
FIM

// Inicia uma Thread
PROCEDURE StartThread(pID é string)
FOR EACH t DE arrThreads
SE t.ID = pID ENTÃO
ThreadExecute(pID, threadNormal, t.Callback)
Trace("▶ Thread [" + pID + "] iniciada")
RETORNAR
FIM
FIM
Trace("❌ Thread não encontrada: " + pID)
FIM

// Adiciona uma Multi-Thread
PROCEDURE AddMultiThread(pID é string, pCallback é Procedure)
t é Thread
t.ID = pID
t.Callback = pCallback
ThreadExecute(pID, threadNormal, t.Callback)
ArrayAdd(arrMultiThreads, t)
Trace("✅ Multi-Thread adicionada: " + pID)
FIM

// Inicia uma Multi-Thread
PROCEDURE StartMultiThread(pID é string)
FOR EACH t DE arrMultiThreads
SE t.ID = pID ENTÃO
ThreadExecute(pID, threadNormal, t.Callback)
Trace("▶ Multi-Thread [" + pID + "] iniciada")
RETORNAR
FIM
FIM
Trace("❌ Multi-Thread não encontrada: " + pID)
FIM

// Lista todos os Timers
PROCEDURE ListTimers()
FOR EACH t DE arrTimers
Trace("Timer: " + t.ID + " | Intervalo: " + t.Intervalo + "ms")
FIM
FIM

// Lista todas as Threads
PROCEDURE ListThreads()
FOR EACH t DE arrThreads
Trace("Thread: " + t.ID)
FIM
FIM

// Lista todas as Multi-Threads
PROCEDURE ListMultiThreads()
FOR EACH t DE arrMultiThreads
Trace("Multi-Thread: " + t.ID)
FIM
FIM

FIM




🔧 Exemplo de Uso

// Criar instância da classe
executions é clsUberExecutions

// Callbacks para cada tipo de execução
PROCEDURE TimerCallback()
Trace("⏱ Timer executado: " + TimeSys())

PROCEDURE ThreadCallback()
Trace("🧵 Thread executada: " + TimeSys())

PROCEDURE MultiThreadCallback()
Trace("🔄 Multi-Thread executada: " + TimeSys())

// Adicionar e iniciar um Timer
executions.AddTimer("Timer1", 2000, TimerCallback)
executions.StartTimer("Timer1")

// Adicionar e iniciar uma Thread
executions.AddThread("Thread1", ThreadCallback)
executions.StartThread("Thread1")

// Adicionar e iniciar uma Multi-Thread
executions.AddMultiThread("MultiThread1", MultiThreadCallback)
executions.StartMultiThread("MultiThread1")

// Listar todas as execuções
executions.ListTimers()
executions.ListThreads()
executions.ListMultiThreads()




✅ Recursos da Classe clsUberExecutions
• Timers: Utiliza o método Timer() para executar funções em intervalos regulares, ideal para tarefas periódicas.
• Threads: Utiliza ThreadExecute() para executar funções em segundo plano, permitindo a execução simultânea de múltiplas tarefas.
• Multi-Threads: Similar às Threads, mas permite a execução de múltiplas instâncias da mesma função em paralelo, útil para operações independentes que podem ser realizadas simultaneamente.
• Controle Completo: Métodos para adicionar, iniciar e listar Timers, Threads e Multi-Threads, proporcionando flexibilidade no gerenciamento das execuções.

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/
Membro registado
4.618 mensagems
Publicado em agosto, 29 2025 - 1:49 AM
Boa noite 😎

Vamos criar um exemplo completo de uso da classe clsUberExecutions, mostrando Timers, Threads e Multi-Threads funcionando juntos, simulando tarefas de um app estilo Uber.



🔧 Exemplo de Uso – clsUberExecutions

// Criar instância da classe
executions é clsUberExecutions

// ==============================
// Callbacks para cada tipo de execução
// ==============================

// Timer: atualizar GPS
PROCEDURE Timer_GPS()
Trace("📍 Timer GPS atualizado: " + TimeSys())

// Thread: verificar mensagens
PROCEDURE Thread_Chat()
Trace("💬 Thread Chat executada: " + TimeSys())

// Multi-Thread: atualizar UI
PROCEDURE MultiThread_UI()
Trace("🖥 Multi-Thread UI atualizada: " + TimeSys())

// ==============================
// Adicionar execuções
// ==============================

// Timer a cada 2 segundos
executions.AddTimer("TimerGPS", 2000, Timer_GPS)
executions.StartTimer("TimerGPS")

// Thread única
executions.AddThread("ThreadChat", Thread_Chat)
executions.StartThread("ThreadChat")

// Multi-Thread – pode criar várias instâncias se quiser
executions.AddMultiThread("UIThread1", MultiThread_UI)
executions.AddMultiThread("UIThread2", MultiThread_UI)
executions.StartMultiThread("UIThread1")
executions.StartMultiThread("UIThread2")

// ==============================
// Listar todas as execuções
// ==============================
executions.ListTimers()
executions.ListThreads()
executions.ListMultiThreads()

// ==============================
// Pausar e continuar
// ==============================
// (Para pausar ou continuar, basta implementar flags dentro do callback)




✅ Funcionalidade deste exemplo
1. Timer (TimerGPS): executa a cada 2 segundos para simular atualização do GPS.
2. Thread (ThreadChat): executa em background para simular verificação de mensagens.
3. Multi-Thread (UIThread1, UIThread2): executa múltiplas threads em paralelo para simular atualização de UI.
4. Listagem: imprime o status de todos os Timers, Threads e Multi-Threads.
5. Expansível: você pode adicionar mais timers ou threads conforme necessidade.



--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/
Membro registado
4.618 mensagems
Publicado em agosto, 29 2025 - 2:13 AM
//=============================================================================
// Classe: clsTimer
// Finalidade: Controle avançado de timers com funcionalidades completas
// Autor: Baseado na análise do fórum PcSoft
// Versão: 1.0
// Data: 28/08/2025
//=============================================================================

CLASS clsTimer

//=============================================================================
// ATRIBUTOS PRIVADOS
//=============================================================================
PRIVATE
m_nTimerID IS INT = -1 // ID único do timer
m_nIntervaloMS IS INT = 1000 // Intervalo em milissegundos
m_bAtivo IS BOOLEAN = False // Flag de timer ativo
m_bPausado IS BOOLEAN = False // Flag de timer pausado
m_sProcedureTarget IS STRING = "" // Nome da procedure callback
m_nUltimaExecucao IS INT = 0 // Timestamp da última execução
m_nTempoRestante IS INT = 0 // Tempo restante quando pausado
m_sUUID IS STRING = "" // Identificador único da instância

//=============================================================================
// MÉTODOS PÚBLICOS
//=============================================================================
PUBLIC

//-----------------------------------------------------------------------------
// Constructor: Inicializa a instância do timer
//-----------------------------------------------------------------------------
PROCEDURE Constructor(pProcedureTarget IS STRING = "", pIntervaloMS IS INT = 1000)
TRY
// Validação de parâmetros
IF pIntervaloMS <= 0 THEN
pIntervaloMS = 1000
END

// Inicialização dos atributos
m_sUUID = SysUUID()
m_sProcedureTarget = pProcedureTarget
m_nIntervaloMS = pIntervaloMS
m_bAtivo = False
m_bPausado = False
m_nTimerID = -1
m_nUltimaExecucao = 0
m_nTempoRestante = pIntervaloMS

Trace("[Timer:" + m_sUUID + "] Instância criada com intervalo de " + m_nIntervaloMS + "ms")

EXCEPTION
Error("Erro na inicialização do Timer: " + ExceptionInfo())
END
END

//-----------------------------------------------------------------------------
// Destructor: Limpa recursos ao destruir a instância
//-----------------------------------------------------------------------------
PROCEDURE Destructor()
TRY
Timer_Stop()
Trace("[Timer:" + m_sUUID + "] Instância destruída")
EXCEPTION
// Log silencioso para evitar erros na destruição
END
END

//-----------------------------------------------------------------------------
// Timer_Play: Inicia o timer com procedure e intervalo especificados
//-----------------------------------------------------------------------------
PROCEDURE Timer_Play(pIntervaloMS IS INT = 0, pProcedureTarget IS STRING = "")
TRY
// Para timer existente se estiver rodando
IF m_nTimerID <> -1 THEN
Timer_Stop()
END

// Atualiza parâmetros se fornecidos
IF pIntervaloMS > 0 THEN
m_nIntervaloMS = pIntervaloMS
END

IF pProcedureTarget <> "" THEN
m_sProcedureTarget = pProcedureTarget
END

// Validação da procedure
IF m_sProcedureTarget = "" THEN
Error("Procedure target não definida para o timer")
RETURN False
END

// Inicia o timer
m_nTimerID = TimerSys(m_nIntervaloMS, m_sProcedureTarget)

IF m_nTimerID <> -1 THEN
m_bAtivo = True
m_bPausado = False
m_nUltimaExecucao = TimeSys()
m_nTempoRestante = m_nIntervaloMS

Trace("[Timer:" + m_sUUID + "] Timer iniciado - ID: " + m_nTimerID + ", Intervalo: " + m_nIntervaloMS + "ms")
RETURN True
ELSE
Error("Falha ao criar timer do sistema")
RETURN False
END

EXCEPTION
Error("Erro ao iniciar timer: " + ExceptionInfo())
RETURN False
END
END

//-----------------------------------------------------------------------------
// Timer_Stop: Para completamente o timer
//-----------------------------------------------------------------------------
PROCEDURE Timer_Stop()
TRY
IF m_nTimerID <> -1 THEN
TimerSys(m_nTimerID) // Remove o timer
Trace("[Timer:" + m_sUUID + "] Timer parado - ID: " + m_nTimerID)
END

// Reset dos estados
m_nTimerID = -1
m_bAtivo = False
m_bPausado = False
m_nUltimaExecucao = 0
m_nTempoRestante = m_nIntervaloMS

RETURN True

EXCEPTION
Error("Erro ao parar timer: " + ExceptionInfo())
RETURN False
END
END

//-----------------------------------------------------------------------------
// Timer_Pause: Pausa o timer preservando o estado
//-----------------------------------------------------------------------------
PROCEDURE Timer_Pause()
TRY
IF m_bAtivo AND NOT m_bPausado THEN
// Calcula tempo restante
LOCAL nTempoDecorrido IS INT = TimeSys() - m_nUltimaExecucao
m_nTempoRestante = m_nIntervaloMS - nTempoDecorrido

IF m_nTempoRestante < 0 THEN
m_nTempoRestante = 0
END

// Para o timer temporariamente
TimerSys(m_nTimerID)
m_nTimerID = -1
m_bPausado = True

Trace("[Timer:" + m_sUUID + "] Timer pausado - Tempo restante: " + m_nTempoRestante + "ms")
RETURN True
END

RETURN False

EXCEPTION
Error("Erro ao pausar timer: " + ExceptionInfo())
RETURN False
END
END

//-----------------------------------------------------------------------------
// Timer_Continue: Continua o timer do ponto onde foi pausado
//-----------------------------------------------------------------------------
PROCEDURE Timer_Continue()
TRY
IF m_bPausado AND m_bAtivo THEN
// Reinicia com o tempo restante
m_nTimerID = TimerSys(m_nTempoRestante, m_sProcedureTarget)

IF m_nTimerID <> -1 THEN
m_bPausado = False
m_nUltimaExecucao = TimeSys() - (m_nIntervaloMS - m_nTempoRestante)

Trace("[Timer:" + m_sUUID + "] Timer continuado - ID: " + m_nTimerID)
RETURN True
ELSE
Error("Falha ao retomar timer")
RETURN False
END
END

RETURN False

EXCEPTION
Error("Erro ao continuar timer: " + ExceptionInfo())
RETURN False
END
END

//-----------------------------------------------------------------------------
// Timer_SetInterval: Altera o intervalo e reinicia o timer
//-----------------------------------------------------------------------------
PROCEDURE Timer_SetInterval(pNovoIntervalo IS INT)
TRY
IF pNovoIntervalo <= 0 THEN
Error("Intervalo deve ser maior que zero")
RETURN False
END

LOCAL bEstavRodando IS BOOLEAN = m_bAtivo AND NOT m_bPausado

// Para o timer atual
Timer_Stop()

// Atualiza o intervalo
m_nIntervaloMS = pNovoIntervalo

// Reinicia se estava rodando
IF bEstavRodando THEN
Timer_Play()
END

Trace("[Timer:" + m_sUUID + "] Intervalo alterado para: " + pNovoIntervalo + "ms")
RETURN True

EXCEPTION
Error("Erro ao alterar intervalo: " + ExceptionInfo())
RETURN False
END
END

//=============================================================================
// MÉTODOS DE CONSULTA (GETTERS)
//=============================================================================

//-----------------------------------------------------------------------------
// IsActive: Retorna se o timer está ativo
//-----------------------------------------------------------------------------
PROCEDURE IsActive()
RETURN m_bAtivo
END

//-----------------------------------------------------------------------------
// IsPaused: Retorna se o timer está pausado
//-----------------------------------------------------------------------------
PROCEDURE IsPaused()
RETURN m_bPausado
END

//-----------------------------------------------------------------------------
// GetInterval: Retorna o intervalo atual em milissegundos
//-----------------------------------------------------------------------------
PROCEDURE GetInterval()
RETURN m_nIntervaloMS
END

//-----------------------------------------------------------------------------
// GetTimerID: Retorna o ID do timer do sistema
//-----------------------------------------------------------------------------
PROCEDURE GetTimerID()
RETURN m_nTimerID
END

//-----------------------------------------------------------------------------
// GetUUID: Retorna o identificador único da instância
//-----------------------------------------------------------------------------
PROCEDURE GetUUID()
RETURN m_sUUID
END

//-----------------------------------------------------------------------------
// GetStatus: Retorna string com status detalhado do timer
//-----------------------------------------------------------------------------
PROCEDURE GetStatus()
LOCAL sStatus IS STRING = "[Timer:" + m_sUUID + "] "

IF m_bAtivo THEN
IF m_bPausado THEN
sStatus += "PAUSADO (Restante: " + m_nTempoRestante + "ms)"
ELSE
sStatus += "ATIVO (Intervalo: " + m_nIntervaloMS + "ms)"
END
ELSE
sStatus += "PARADO"
END

RETURN sStatus
END

END

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/
Membro registado
4.618 mensagems
Publicado em agosto, 29 2025 - 2:13 AM
//=============================================================================
// Classe: clsThread
// Finalidade: Controle avançado de threads para execução assíncrona
// Autor: Baseado na análise do fórum PcSoft
// Versão: 1.0
// Data: 28/08/2025
//=============================================================================

CLASS clsThread

//=============================================================================
// ATRIBUTOS PRIVADOS
//=============================================================================
PRIVATE
m_sThreadID IS STRING = "" // ID único da thread
m_sProcedureTarget IS STRING = "" // Nome da procedure a executar
m_bRodando IS BOOLEAN = False // Flag de thread ativa
m_bPausada IS BOOLEAN = False // Flag de thread pausada
m_bTerminar IS BOOLEAN = False // Flag para terminar thread
m_nPrioridade IS INT = threadNormal // Prioridade da thread
m_sUUID IS STRING = "" // Identificador único da instância
m_nTempoInicio IS INT = 0 // Timestamp de início
m_nTempoExecucao IS INT = 0 // Tempo total de execução
m_bLoop IS BOOLEAN = False // Flag para execução em loop
m_nIntervaloLoop IS INT = 100 // Intervalo entre execuções do loop

//=============================================================================
// MÉTODOS PÚBLICOS
//=============================================================================
PUBLIC

//-----------------------------------------------------------------------------
// Constructor: Inicializa a instância da thread
//-----------------------------------------------------------------------------
PROCEDURE Constructor(pProcedureTarget IS STRING = "", pPrioridade IS INT = threadNormal)
TRY
// Inicialização dos atributos
m_sUUID = SysUUID()
m_sThreadID = "THR_" + m_sUUID
m_sProcedureTarget = pProcedureTarget
m_nPrioridade = pPrioridade
m_bRodando = False
m_bPausada = False
m_bTerminar = False
m_nTempoInicio = 0
m_nTempoExecucao = 0
m_bLoop = False
m_nIntervaloLoop = 100

Trace("[Thread:" + m_sUUID + "] Instância criada")

EXCEPTION
Error("Erro na inicialização da Thread: " + ExceptionInfo())
END
END

//-----------------------------------------------------------------------------
// Destructor: Limpa recursos ao destruir a instância
//-----------------------------------------------------------------------------
PROCEDURE Destructor()
TRY
Thread_Stop()
Trace("[Thread:" + m_sUUID + "] Instância destruída")
EXCEPTION
// Log silencioso para evitar erros na destruição
END
END

//-----------------------------------------------------------------------------
// Thread_Start: Inicia a execução da thread
//-----------------------------------------------------------------------------
PROCEDURE Thread_Start(pProcedureTarget IS STRING = "", pPrioridade IS INT = 0)
TRY
// Para thread existente se estiver rodando
IF m_bRodando THEN
Thread_Stop()
END

// Atualiza parâmetros se fornecidos
IF pProcedureTarget <> "" THEN
m_sProcedureTarget = pProcedureTarget
END

IF pPrioridade <> 0 THEN
m_nPrioridade = pPrioridade
END

// Validação da procedure
IF m_sProcedureTarget = "" THEN
Error("Procedure target não definida para a thread")
RETURN False
END

// Reset dos flags de controle
m_bTerminar = False
m_bPausada = False

// Inicia a thread
LOCAL bResultado IS BOOLEAN = ThreadExecute(m_sThreadID, m_nPrioridade, Thread_ExecuteWrapper)

IF bResultado THEN
m_bRodando = True
m_nTempoInicio = TimeSys()

Trace("[Thread:" + m_sUUID + "] Thread iniciada - ID: " + m_sThreadID)
RETURN True
ELSE
Error("Falha ao criar thread")
RETURN False
END

EXCEPTION
Error("Erro ao iniciar thread: " + ExceptionInfo())
RETURN False
END
END

//-----------------------------------------------------------------------------
// Thread_StartLoop: Inicia a thread em modo loop contínuo
//-----------------------------------------------------------------------------
PROCEDURE Thread_StartLoop(pProcedureTarget IS STRING = "", pIntervaloMS IS INT = 100, pPrioridade IS INT = 0)
TRY
// Configura modo loop
m_bLoop = True
m_nIntervaloLoop = pIntervaloMS

// Inicia a thread
RETURN Thread_Start(pProcedureTarget, pPrioridade)

EXCEPTION
Error("Erro ao iniciar thread em loop: " + ExceptionInfo())
RETURN False
END
END

//-----------------------------------------------------------------------------
// Thread_Stop: Para completamente a thread
//-----------------------------------------------------------------------------
PROCEDURE Thread_Stop()
TRY
IF m_bRodando THEN
// Sinaliza para terminar
m_bTerminar = True

// Aguarda um pouco para término graceful
Multitask(50)

// Força o término se necessário
ThreadKill(m_sThreadID)

// Calcula tempo de execução
IF m_nTempoInicio > 0 THEN
m_nTempoExecucao = TimeSys() - m_nTempoInicio
END

Trace("[Thread:" + m_sUUID + "] Thread parada - Tempo execução: " + m_nTempoExecucao + "ms")
END

// Reset dos estados
m_bRodando = False
m_bPausada = False
m_bTerminar = False
m_bLoop = False

RETURN True

EXCEPTION
Error("Erro ao parar thread: " + ExceptionInfo())
RETURN False
END
END

//-----------------------------------------------------------------------------
// Thread_Pause: Pausa a execução da thread
//-----------------------------------------------------------------------------
PROCEDURE Thread_Pause()
TRY
IF m_bRodando AND NOT m_bPausada THEN
m_bPausada = True
Trace("[Thread:" + m_sUUID + "] Thread pausada")
RETURN True
END

RETURN False

EXCEPTION
Error("Erro ao pausar thread: " + ExceptionInfo())
RETURN False
END
END

//-----------------------------------------------------------------------------
// Thread_Resume: Retoma a execução da thread
//-----------------------------------------------------------------------------
PROCEDURE Thread_Resume()
TRY
IF m_bRodando AND m_bPausada THEN
m_bPausada = False
Trace("[Thread:" + m_sUUID + "] Thread retomada")
RETURN True
END

RETURN False

EXCEPTION
Error("Erro ao retomar thread: " + ExceptionInfo())
RETURN False
END
END

//-----------------------------------------------------------------------------
// Thread_Wait: Aguarda o término da thread
//-----------------------------------------------------------------------------
PROCEDURE Thread_Wait(pTimeoutMS IS INT = 0)
TRY
LOCAL nInicio IS INT = TimeSys()

WHILE m_bRodando
Multitask(10)

// Verifica timeout se especificado
IF pTimeoutMS > 0 AND (TimeSys() - nInicio) > pTimeoutMS THEN
RETURN False // Timeout
END
END

RETURN True // Thread terminou

EXCEPTION
Error("Erro ao aguardar thread: " + ExceptionInfo())
RETURN False
END
END

//=============================================================================
// MÉTODOS PRIVADOS
//=============================================================================
PRIVATE

//-----------------------------------------------------------------------------
// Thread_ExecuteWrapper: Wrapper para execução da thread
//-----------------------------------------------------------------------------
PROCEDURE Thread_ExecuteWrapper()
TRY
Trace("[Thread:" + m_sUUID + "] Iniciando execução")

IF m_bLoop THEN
// Execução em loop
WHILE NOT m_bTerminar
IF NOT m_bPausada THEN
// Executa a procedure via indirection
IndirectExecute(m_sProcedureTarget, ieProcedure)
END

// Pausa entre execuções
ThreadPause(m_nIntervaloLoop)
END
ELSE
// Execução única
IF NOT m_bTerminar AND NOT m_bPausada THEN
IndirectExecute(m_sProcedureTarget, ieProcedure)
END
END

Trace("[Thread:" + m_sUUID + "] Execução finalizada")

EXCEPTION
Error("[Thread:" + m_sUUID + "] Erro na execução: " + ExceptionInfo())
FINALLY
m_bRodando = False
END
END

//=============================================================================
// MÉTODOS DE CONSULTA (GETTERS)
//=============================================================================
PUBLIC

//-----------------------------------------------------------------------------
// IsRunning: Retorna se a thread está rodando
//-----------------------------------------------------------------------------
PROCEDURE IsRunning()
RETURN m_bRodando
END

//-----------------------------------------------------------------------------
// IsPaused: Retorna se a thread está pausada
//-----------------------------------------------------------------------------
PROCEDURE IsPaused()
RETURN m_bPausada
END

//-----------------------------------------------------------------------------
// IsLoop: Retorna se a thread está em modo loop
//-----------------------------------------------------------------------------
PROCEDURE IsLoop()
RETURN m_bLoop
END

//-----------------------------------------------------------------------------
// GetThreadID: Retorna o ID da thread
//-----------------------------------------------------------------------------
PROCEDURE GetThreadID()
RETURN m_sThreadID
END

//-----------------------------------------------------------------------------
// GetUUID: Retorna o identificador único da instância
//-----------------------------------------------------------------------------
PROCEDURE GetUUID()
RETURN m_sUUID
END

//-----------------------------------------------------------------------------
// GetExecutionTime: Retorna o tempo de execução em milissegundos
//-----------------------------------------------------------------------------
PROCEDURE GetExecutionTime()
IF m_bRodando AND m_nTempoInicio > 0 THEN
RETURN TimeSys() - m_nTempoInicio
ELSE
RETURN m_nTempoExecucao
END
END

//-----------------------------------------------------------------------------
// GetStatus: Retorna string com status detalhado da thread
//-----------------------------------------------------------------------------
PROCEDURE GetStatus()
LOCAL sStatus IS STRING = "[Thread:" + m_sUUID + "] "

IF m_bRodando THEN
IF m_bPausada THEN
sStatus += "PAUSADA"
ELSE
sStatus += "RODANDO"
END

IF m_bLoop THEN
sStatus += " (LOOP: " + m_nIntervaloLoop + "ms)"
END

sStatus += " - Tempo: " + GetExecutionTime() + "ms"
ELSE
sStatus += "PARADA"
IF m_nTempoExecucao > 0 THEN
sStatus += " - Último tempo: " + m_nTempoExecucao + "ms"
END
END

RETURN sStatus
END

END

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/
Membro registado
4.618 mensagems
Publicado em agosto, 29 2025 - 2:14 AM
//=============================================================================
// Classe: clsMultiThread
// Finalidade: Gerenciamento coordenado de múltiplas threads
// Autor: Baseado na análise do fórum PcSoft
// Versão: 1.0
// Data: 28/08/2025
//=============================================================================

CLASS clsMultiThread

//=============================================================================
// ATRIBUTOS PRIVADOS
//=============================================================================
PRIVATE
m_arrThreads IS ARRAY OF clsThread // Array de threads gerenciadas
m_arrThreadIDs IS ARRAY OF STRING // IDs das threads para controle
m_nMaxThreads IS INT = 10 // Número máximo de threads simultâneas
m_bRodando IS BOOLEAN = False // Flag do gerenciador ativo
m_sUUID IS STRING = "" // Identificador único da instância
m_nThreadsAtivas IS INT = 0 // Contador de threads ativas
m_nThreadsCriadas IS INT = 0 // Contador total de threads criadas
m_bAutoCleanup IS BOOLEAN = True // Limpeza automática de threads finalizadas
m_nIntervaloMonitor IS INT = 500 // Intervalo de monitoramento em ms
m_oThreadMonitor IS clsThread // Thread de monitoramento interno

//=============================================================================
// MÉTODOS PÚBLICOS
//=============================================================================
PUBLIC

//-----------------------------------------------------------------------------
// Constructor: Inicializa o gerenciador de múltiplas threads
//-----------------------------------------------------------------------------
PROCEDURE Constructor(pMaxThreads IS INT = 10, pAutoCleanup IS BOOLEAN = True)
TRY
// Inicialização dos atributos
m_sUUID = SysUUID()
m_nMaxThreads = pMaxThreads
m_bAutoCleanup = pAutoCleanup
m_bRodando = False
m_nThreadsAtivas = 0
m_nThreadsCriadas = 0
m_nIntervaloMonitor = 500

// Inicializa arrays
ArrayDeleteAll(m_arrThreads)
ArrayDeleteAll(m_arrThreadIDs)

// Cria thread de monitoramento
m_oThreadMonitor = new clsThread("", threadNormal)

Trace("[MultiThread:" + m_sUUID + "] Gerenciador criado - Max threads: " + m_nMaxThreads)

EXCEPTION
Error("Erro na inicialização do MultiThread: " + ExceptionInfo())
END
END

//-----------------------------------------------------------------------------
// Destructor: Limpa todos os recursos
//-----------------------------------------------------------------------------
PROCEDURE Destructor()
TRY
MultiThread_StopAll()

// Destrói thread de monitoramento
IF m_oThreadMonitor <> Null THEN
delete m_oThreadMonitor
END

Trace("[MultiThread:" + m_sUUID + "] Gerenciador destruído")
EXCEPTION
// Log silencioso para evitar erros na destruição
END
END

//-----------------------------------------------------------------------------
// MultiThread_Start: Inicia o gerenciador
//-----------------------------------------------------------------------------
PROCEDURE MultiThread_Start()
TRY
IF NOT m_bRodando THEN
m_bRodando = True

// Inicia monitoramento se auto cleanup estiver ativo
IF m_bAutoCleanup THEN
m_oThreadMonitor.Thread_StartLoop("MultiThread_MonitorThreads", m_nIntervaloMonitor)
END

Trace("[MultiThread:" + m_sUUID + "] Gerenciador iniciado")
RETURN True
END

RETURN False

EXCEPTION
Error("Erro ao iniciar MultiThread: " + ExceptionInfo())
RETURN False
END
END

//-----------------------------------------------------------------------------
// MultiThread_Stop: Para o gerenciador e todas as threads
//-----------------------------------------------------------------------------
PROCEDURE MultiThread_StopAll()
TRY
// Para thread de monitoramento
IF m_oThreadMonitor <> Null THEN
m_oThreadMonitor.Thread_Stop()
END

// Para todas as threads gerenciadas
LOCAL i IS INT
FOR i = 1 TO ArrayCount(m_arrThreads)
IF m_arrThreads[i] <> Null THEN
m_arrThreads[i].Thread_Stop()
delete m_arrThreads[i]
END
END

// Limpa arrays
ArrayDeleteAll(m_arrThreads)
ArrayDeleteAll(m_arrThreadIDs)

// Reset contadores
m_nThreadsAtivas = 0
m_bRodando = False

Trace("[MultiThread:" + m_sUUID + "] Todas as threads paradas")
RETURN True

EXCEPTION
Error("Erro ao parar MultiThread: " + ExceptionInfo())
RETURN False
END
END

//-----------------------------------------------------------------------------
// AddThread: Adiciona uma nova thread ao pool
//-----------------------------------------------------------------------------
PROCEDURE AddThread(pProcedureTarget IS STRING, pPrioridade IS INT = threadNormal, pAutoStart IS BOOLEAN = True)
TRY
// Verifica limite de threads
IF ArrayCount(m_arrThreads) >= m_nMaxThreads THEN
Error("Limite máximo de threads atingido: " + m_nMaxThreads)
RETURN ""
END

// Cria nova thread
LOCAL oNovaThread IS clsThread = new clsThread(pProcedureTarget, pPrioridade)

IF oNovaThread <> Null THEN
// Adiciona aos arrays
ArrayAdd(m_arrThreads, oNovaThread)
ArrayAdd(m_arrThreadIDs, oNovaThread.GetUUID())

m_nThreadsCriadas++

// Inicia automaticamente se solicitado
IF pAutoStart THEN
oNovaThread.Thread_Start()
m_nThreadsAtivas++
END

LOCAL sThreadID IS STRING = oNovaThread.GetUUID()
Trace("[MultiThread:" + m_sUUID + "] Thread adicionada: " + sThreadID)

RETURN sThreadID
ELSE
Error("Falha ao criar nova thread")
RETURN ""
END

EXCEPTION
Error("Erro ao adicionar thread: " + ExceptionInfo())
RETURN ""
END
END

//-----------------------------------------------------------------------------
// AddLoopThread: Adiciona uma thread em modo loop
//-----------------------------------------------------------------------------
PROCEDURE AddLoopThread(pProcedureTarget IS STRING, pIntervaloMS IS INT = 100, pPrioridade IS INT = threadNormal, pAutoStart IS BOOLEAN = True)
TRY
// Verifica limite de threads
IF ArrayCount(m_arrThreads) >= m_nMaxThreads THEN
Error("Limite máximo de threads atingido: " + m_nMaxThreads)
RETURN ""
END

// Cria nova thread
LOCAL oNovaThread IS clsThread = new clsThread(pProcedureTarget, pPrioridade)

IF oNovaThread <> Null THEN
// Adiciona aos arrays
ArrayAdd(m_arrThreads, oNovaThread)
ArrayAdd(m_arrThreadIDs, oNovaThread.GetUUID())

m_nThreadsCriadas++

// Inicia em modo loop se solicitado
IF pAutoStart THEN
oNovaThread.Thread_StartLoop(pProcedureTarget, pIntervaloMS, pPrioridade)
m_nThreadsAtivas++
END

LOCAL sThreadID IS STRING = oNovaThread.GetUUID()
Trace("[MultiThread:" + m_sUUID + "] Thread loop adicionada: " + sThreadID + " (Intervalo: " + pIntervaloMS + "ms)")

RETURN sThreadID
ELSE
Error("Falha ao criar nova thread loop")
RETURN ""
END

EXCEPTION
Error("Erro ao adicionar thread loop: " + ExceptionInfo())
RETURN ""
END
END

//-----------------------------------------------------------------------------
// RemoveThread: Remove uma thread específica
//-----------------------------------------------------------------------------
PROCEDURE RemoveThread(pThreadID IS STRING)
TRY
LOCAL nIndice IS INT = FindThreadIndex(pThreadID)

IF nIndice > 0 THEN
// Para a thread
m_arrThreads[nIndice].Thread_Stop()

// Remove da memória
delete m_arrThreads[nIndice]

// Remove dos arrays
ArrayDelete(m_arrThreads, nIndice)
ArrayDelete(m_arrThreadIDs, nIndice)

// Atualiza contador
IF m_nThreadsAtivas > 0 THEN
m_nThreadsAtivas--
END

Trace("[MultiThread:" + m_sUUID + "] Thread removida: " + pThreadID)
RETURN True
ELSE
Error("Thread não encontrada: " + pThreadID)
RETURN False
END

EXCEPTION
Error("Erro ao remover thread: " + ExceptionInfo())
RETURN False
END
END

//-----------------------------------------------------------------------------
// StartThread: Inicia uma thread específica
//-----------------------------------------------------------------------------
PROCEDURE StartThread(pThreadID IS STRING)
TRY
LOCAL nIndice IS INT = FindThreadIndex(pThreadID)

IF nIndice > 0 THEN
IF m_arrThreads[nIndice].Thread_Start() THEN
m_nThreadsAtivas++
Trace("[MultiThread:" + m_sUUID + "] Thread iniciada: " + pThreadID)
RETURN True
END
ELSE
Error("Thread não encontrada: " + pThreadID)
END

RETURN False

EXCEPTION
Error("Erro ao iniciar thread: " + ExceptionInfo())
RETURN False
END
END

//-----------------------------------------------------------------------------
// StopThread: Para uma thread específica
//-----------------------------------------------------------------------------
PROCEDURE StopThread(pThreadID IS STRING)
TRY
LOCAL nIndice IS INT = FindThreadIndex(pThreadID)

IF nIndice > 0 THEN
IF m_arrThreads[nIndice].Thread_Stop() THEN
IF m_nThreadsAtivas > 0 THEN
m_nThreadsAtivas--
END
Trace("[MultiThread:" + m_sUUID + "] Thread parada: " + pThreadID)
RETURN True
END
ELSE
Error("Thread não encontrada: " + pThreadID)
END

RETURN False

EXCEPTION
Error("Erro ao parar thread: " + ExceptionInfo())
RETURN False
END
END

//-----------------------------------------------------------------------------
// PauseThread: Pausa uma thread específica
//-----------------------------------------------------------------------------
PROCEDURE PauseThread(pThreadID IS STRING)
TRY
LOCAL nIndice IS INT = FindThreadIndex(pThreadID)

IF nIndice > 0 THEN
RETURN m_arrThreads[nIndice].Thread_Pause()
ELSE
Error("Thread não encontrada: " + pThreadID)
RETURN False
END

EXCEPTION
Error("Erro ao pausar thread: " + ExceptionInfo())
RETURN False
END
END

//-----------------------------------------------------------------------------
// ResumeThread: Retoma uma thread específica
//-----------------------------------------------------------------------------
PROCEDURE ResumeThread(pThreadID IS STRING)
TRY
LOCAL nIndice IS INT = FindThreadIndex(pThreadID)

IF nIndice > 0 THEN
RETURN m_arrThreads[nIndice].Thread_Resume()
ELSE
Error("Thread não encontrada: " + pThreadID)
RETURN False
END

EXCEPTION
Error("Erro ao retomar thread: " + ExceptionInfo())
RETURN False
END
END

//-----------------------------------------------------------------------------
// WaitAllThreads: Aguarda o término de todas as threads
//-----------------------------------------------------------------------------
PROCEDURE WaitAllThreads(pTimeoutMS IS INT = 0)
TRY
LOCAL nInicio IS INT = TimeSys()
LOCAL i IS INT

WHILE m_nThreadsAtivas > 0
// Verifica cada thread
FOR i = 1 TO ArrayCount(m_arrThreads)
IF m_arrThreads[i] <> Null THEN
IF NOT m_arrThreads[i].IsRunning() THEN
// Thread terminou, atualiza contador
IF m_nThreadsAtivas > 0 THEN
m_nThreadsAtivas--
END
END
END
END

Multitask(50)

// Verifica timeout se especificado
IF pTimeoutMS > 0 AND (TimeSys() - nInicio) > pTimeoutMS THEN
RETURN False // Timeout
END
END

RETURN True // Todas as threads terminaram

EXCEPTION
Error("Erro ao aguardar threads: " + ExceptionInfo())
RETURN False
END
END

//=============================================================================
// MÉTODOS PRIVADOS
//=============================================================================
PRIVATE

//-----------------------------------------------------------------------------
// FindThreadIndex: Encontra o índice de uma thread pelo ID
//-----------------------------------------------------------------------------
PROCEDURE FindThreadIndex(pThreadID IS STRING)
LOCAL i IS INT

FOR i = 1 TO ArrayCount(m_arrThreadIDs)
IF m_arrThreadIDs[i] = pThreadID THEN
RETURN i
END
END

RETURN 0 // Não encontrado
END

//-----------------------------------------------------------------------------
// MultiThread_MonitorThreads: Monitora e limpa threads finalizadas
//-----------------------------------------------------------------------------
PROCEDURE MultiThread_MonitorThreads()
TRY
LOCAL i IS INT
LOCAL nThreadsRemovidas IS INT = 0

// Verifica threads finalizadas para limpeza
FOR i = ArrayCount(m_arrThreads) TO 1 STEP -1
IF m_arrThreads[i] <> Null THEN
IF NOT m_arrThreads[i].IsRunning() THEN
// Thread finalizada, remove se auto cleanup estiver ativo
IF m_bAutoCleanup THEN
LOCAL sThreadID IS STRING = m_arrThreads[i].GetUUID()
delete m_arrThreads[i]
ArrayDelete(m_arrThreads, i)
ArrayDelete(m_arrThreadIDs, i)
nThreadsRemovidas++

IF m_nThreadsAtivas > 0 THEN
m_nThreadsAtivas--
END
END
END
END
END

IF nThreadsRemovidas > 0 THEN
Trace("[MultiThread:" + m_sUUID + "] Limpeza automática: " + nThreadsRemovidas + " threads removidas")
END

EXCEPTION
Error("[MultiThread:" + m_sUUID + "] Erro no monitoramento: " + ExceptionInfo())
END
END

//=============================================================================
// MÉTODOS DE CONSULTA (GETTERS)
//=============================================================================
PUBLIC

//-----------------------------------------------------------------------------
// GetActiveThreadsCount: Retorna o número de threads ativas
//-----------------------------------------------------------------------------
PROCEDURE GetActiveThreadsCount()
RETURN m_nThreadsAtivas
END

//-----------------------------------------------------------------------------
// GetTotalThreadsCount: Retorna o número total de threads gerenciadas
//-----------------------------------------------------------------------------
PROCEDURE GetTotalThreadsCount()
RETURN ArrayCount(m_arrThreads)
END

//-----------------------------------------------------------------------------
// GetCreatedThreadsCount: Retorna o número total de threads criadas
//-----------------------------------------------------------------------------
PROCEDURE GetCreatedThreadsCount()
RETURN m_nThreadsCriadas
END

//-----------------------------------------------------------------------------
// GetMaxThreads: Retorna o limite máximo de threads
//-----------------------------------------------------------------------------
PROCEDURE GetMaxThreads()
RETURN m_nMaxThreads
END

//-----------------------------------------------------------------------------
// IsRunning: Retorna se o gerenciador está ativo
//-----------------------------------------------------------------------------
PROCEDURE IsRunning()
RETURN m_bRodando
END

//-----------------------------------------------------------------------------
// GetUUID: Retorna o identificador único da instância
//-----------------------------------------------------------------------------
PROCEDURE GetUUID()
RETURN m_sUUID
END

//-----------------------------------------------------------------------------
// GetThreadIDs: Retorna array com IDs de todas as threads
//-----------------------------------------------------------------------------
PROCEDURE GetThreadIDs()
RETURN m_arrThreadIDs
END

//-----------------------------------------------------------------------------
// GetThreadStatus: Retorna status de uma thread específica
//-----------------------------------------------------------------------------
PROCEDURE GetThreadStatus(pThreadID IS STRING)
LOCAL nIndice IS INT = FindThreadIndex(pThreadID)

IF nIndice > 0 THEN
RETURN m_arrThreads[nIndice].GetStatus()
ELSE
RETURN "Thread não encontrada: " + pThreadID
END
END

//-----------------------------------------------------------------------------
// GetStatus: Retorna string com status detalhado do gerenciador
//-----------------------------------------------------------------------------
PROCEDURE GetStatus()
LOCAL sStatus IS STRING = "[MultiThread:" + m_sUUID + "] "

sStatus += "Ativas: " + m_nThreadsAtivas + "/" + ArrayCount(m_arrThreads)
sStatus += " | Criadas: " + m_nThreadsCriadas
sStatus += " | Max: " + m_nMaxThreads

IF m_bRodando THEN
sStatus += " | Status: RODANDO"
ELSE
sStatus += " | Status: PARADO"
END

IF m_bAutoCleanup THEN
sStatus += " | AutoCleanup: ON"
ELSE
sStatus += " | AutoCleanup: OFF"
END

RETURN sStatus
END

END

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/