Newsgroup: it.comp.lang.visual-basic
Titolo: [VB] Strano Funzionamento Timer

Ciao a tutto il NG,
mettiamo di avere un array di tre timer chiamati objTimerGate con
indice 1,2,3.
Con il seguente codice li inizializzo a scaturire l'evento ogni 50 ms.
Dim lngCounter As Long
    For lngCounter = 1 To BAIE_CARICO
        objTimerGate(lngCounter).Interval = 50
        objTimerGate(lngCounter).Enabled = True
    Next lngCounter
Nella gestione dell'evento metto la chiamata alla sub esegui ciclo
Private Sub objTimerGate_Timer(Index As Integer)
    Call EseguiCiclo(CLng(Index))
End Sub
La esegui ciclo non fa altro che scrivere l'ora in cui parte e l'ora in
cui finisce la gestione del timer chiamante, in mezzo a queste due
operazioni esegue un incremento della variabile dblCounter ed ogni
tanto lascia al sistema la gestione di altri messaggi in coda.
Private Sub EseguiCiclo(lngCounter As Long)
Dim dblCounter As Double
    Call objLog.FileWrite(Format(Now(), "hh:mm:ss") & "  GATES " &
lngCounter & "----> INIZIO Controllo Buffer ed alzo uscite")
    For dblCounter = 1 To 1000000
        If (dblCounter Mod 100000) = 0 Then _
            DoEvents
    Next dblCounter
    Call objLog.FileWrite(Format(Now(), "hh:mm:ss") & "  GATES " &
lngCounter & "----> FINE Controllo Buffer ed alzo uscite")
End Sub
Quello che non capisco è perchè il file di log mi riporta questi dati
14.55.24  GATES 1----> INIZIO Controllo Buffer ed alzo uscite
14.55.24  GATES 2----> INIZIO Controllo Buffer ed alzo uscite
14.55.24  GATES 3----> INIZIO Controllo Buffer ed alzo uscite
14.55.27  GATES 3----> FINE Controllo Buffer ed alzo uscite
14.55.28  GATES 2----> FINE Controllo Buffer ed alzo uscite
14.55.30  GATES 1----> FINE Controllo Buffer ed alzo uscite
Perchè il timer non viene scaturito ugualmente ad ogni timing?
Inoltre se imposto un altro timer objUpdateServer con un intervallo
pari a 5 secondi, l'evento non viene eseguito nemmeno.
C'è qualcosa che mi sfugge?
Grazie a tutti..
oZ

 pari a 5 secondi, l'evento non viene eseguito nemmeno.
Perchè VB6 fa una sola cosa alla volta, tutto il resto va in coda e viene
smazzato appena possibile.
Anzi, stai attento a mettere elaborazioni che potrebbero durare più
dell'intervallo senza niente che controlli questo: potresti continuare ad
accodare richieste di esecuzione e non riuscire a smaltirle.
Ciao
--
Reporting tool: 
http://www.neodatatype.net

accodare richieste di esecuzione e non riuscire a smaltirle.
Intendi spazio di stack esaurito?
Presumo che questo non dovrebbe avvenire nella "mia" realtà, il ciclo
di prima era pompato, ovviamente non possso impostare un timing così
basso per eseguire procedure che durano minuti.
Ciao
oZ

>Procedure parallele (o quasi) che interrogano tramite socket un dispositivo.
Oppss. Ho commesso un errore non indifferente:
sono n procedure parallele (o quasi) che interrogano tramite socket n
dispositivi.
tenendo presente che n<=6
Ciao
oZ

 tenendo presente che n<=6
In VB6 non puoi avere procedure parallele.
Ma i socket, che sappia io sono per natura asincroni e hanno i loro eventi,
senza che tu vada ad interrogarli.
Dai un occhio al controllo Microsoft Winsock al posto delle API.


 potrebbe essere una soluzione?
No perché comunque come ti diceva Zanna VB processa un solo flusso alla volta (è
monothread), di regola.
(Comunque AFAIK i gli eventi timer non si "accodano" se VB non fa in tempo a
processarli perché impegnato, ma vengono persi)
Bye
Raf


Dici?
Mi viene il dubbio.


 Mi viene il dubbio.
Prova: form con 1 timer con interval es. 1000 e un commandbutton nel cui evento
click chiami l'api Sleep con un tempo pari a 10000 ms.
Se premi il command, una volta trascorsi i 10 sec. gli eventi Timer "persi" mica
arrivano tutti in una volta!
Bye
Raf

 eventi Timer "persi" mica arrivano tutti in una volta!
Infatti arrivano uno alla volta nell'ordine in cui sono
stati generati... come ci si aspetterebbe. E nel frattempo
lo stack si riempie.
Prova:
Sul form:
Label: Label1
Timer: Timer1 - Enabled = True  - Interval = 1000
'----- CODICE -----
Option Explicit
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As 
Long)
Private i As Long
Private Sub Timer1_Timer()
    i = i + 1
    Label1.Caption = CStr(i)
    If i = 5 Then Timer1.Enabled = False
    Call Sleep(2000)
End Sub
'----- FINE CODICE -----
Lokar
-- 
Sito Comune: 
http://www.it-lang-vb.net/
Manifesto: 
http://www.it-lang-vb.net/docs/Manifesto.txt
Statuto: 
http://www.it-lang-vb.net/docs/Statuto.txt
 

 Timer: Timer1 - Enabled = True  - Interval = 1000
[CUT]
A mio avviso non dimostra nulla il tuo esempio. Infatti come distingueresti tra
gli eventi serviti dopo essere presumibilmente stati accodati e quelli che si
inseriscono quando il thread è idlë?
E poi considera che se la sleep la piazzi dentro all'evento Timer, da questo non
si esce finché l'attesa non è terminata ed è garantito che altri eventi Timer
non si accodano (per ovvi motivi di rientranza).
Raf

[SNIP]
Rettifico. Il codice che ho postato non prova che ci siano
degli eventi nello stack da processare, ma solo che questi
vengono processati nell'ordine e senza salti. Effettivamente
se si interrompe l'esecuzione di un timer in cui il codice
viene eseguito piu' lentamente dell'interval, gli eventi
"mancanti" non vengono generati. Sottolineo il fatto che
"non vengono generati", non e' infatti vero che vengono
"persi".
Semplicemente l'evento Timer non viene scatenato finche'
non termina l'esecuzione del codice contenuto nell'evento
precedente.
Se nella fattispecie il timer non ritorna al sistema, anche
con un solo DoEvents (e quindi la coda di messaggi per il
processo e' bloccata) nessun altro evento verra' generato,
incluso quello di eventuali altri Timer.
Ecco il test effettuato con 2 timer e 2 label su un form
(Timer1 Timer2 Label1 Label2):
'----- CODICE -----
Option Explicit
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As 
Long)
Private i As Long
Private j As Long
Private Sub Timer1_Timer()
    i = i + 1
    Label1.Caption = CStr(i)
    Call Sleep(2000)
End Sub
Private Sub Timer2_Timer()
    j = j + 1
    Label2.Caption = CStr(j)
    If j = 5 Then
        Timer1.Enabled = False
        Timer2.Enabled = False
    End If
End Sub
'----- FINE CODICE -----
Si noti che sostituendo la funzione Sleep con:
Dim t As Single
t = Timer
Do Until Timer - t > 2
   DoEvents
Loop
L'effetto e' "quasi" equivalente: l'evento Timer di Timer1 non viene 
scatenato e quindi NON si accoda allo stack. L'evento Timer di Timer2 
viene invece eseguito "al momento giusto".
Dall'esecuzione del codice qui sopra si evince che:
- Visual Basic e' single-threaded :)
  Gli eventi del Timer2 vengono scatenati tutti, ma non in
  funzione del tempo definito in Interval, bensi' del tempo
  di esecuzione di tutte le altre funzioni nello stack.
- Gli eventi vengono scatenati e processati contestualmente.
  Finche' l'esecuzione del codice dell'evento Timer non
  termina, NON viene scatenato l'evento successivo.
  In particolare quando il Timer viene disabilitato
  (Enabled = False) non vengono scatenati gli eventi
  "in teoria mancanti". In realta' non ci sono eventi
  mancanti (e quindi neanche eventi persi).
Insomma, nulla di nuovo sotto il sole. Il Timer NON E'
lo strumento adatto a far eseguire un processo con cadenza
fissa.
Il problema dell'OP e' diverso (e devo dire che all'inizio
ho fatto un po' di confusione, non accorgendomi che usava
un'array di controlli timer).
Nel suo caso gli eventi vengono tutti scatenati, poiche'
all'interno del codice dell'evento Timer di ogni Timer
c'e' un DoEvents che permette di tornare al sistema e
di processare il messaggio, N.B., per un timer diverso.
Essendo pero' VB, per l'appunto, single-threaded, l'ultimo
evento generato e' il primo ad essere eseguito fino in
fondo, producendo l'effetto mostrato dall'OP.
Suggerisco, se c'e' la necessita' di monitorare piu'
processi contemporaneamente di usare DLL/EXE ActiveX.
hth,


 rientranza).
Come scritto nell'altro post pero', sostituendo alla Sleep un ciclo 
DoEvents, comunque non si accodano altri eventi timer.
Scusami ancora per il tono spiccio della precedente.


 Lokar
Ciao
Raf

Dai un occhio al controllo Microsoft Winsock al posto delle API
Il cavo è RJ45, ma alla fine c'è un dispositivo seriale, quindi
quando lo interrogo, la risposta mi arriva subito nell'API chiamata.
Potrei implementare il protocollo direttamente sul socket e
ricevere/gestire l'informazione tramite l'evento DataArrival..

processi contemporaneamente di usare DLL/EXE ActiveX
[oZ]
Una DLL viene eseguita in un altro thread dello stesso processo?
Quindi al posto delle mie Form non modali potrei istanziare n DLL?
Oppure taglio la testa al toro e lo faccio in C#...
Il fatto è che mentre in vb ho già le classi per interfacciarmi a SQL
tramite ADO, in C# dovrei riscrivere il tutto (oltre che ovviamente
fare la gestione parallela dei controlli sul socket)..
Grazie a tutti
Ciao

 Ciao
Ciao
Raf