Newsgroup: it.comp.programmare.win32
Titolo: WM_TIMER... e altre soluzioni?

Salve, programmo con il C\C++ e le API di windows. Stavo realizzando
un piccolo programmino e ho un problema. 
Durante l'eecuzione devo effettuare controlli costanti (a brevi
intervalli di tempo) e fino ad'ora ho utilizzato il timer di windows
con invio di messaggi WM_TIMER. Il problema e' che mi chiedevo se
esistesse qualche altro metodo (con piu' alte priorita' dei  messaggi
WM_TIMER) per fare in modo che costantemente possa controllare che sia
passato il tempo giusto per eseguire i controlli. Il metodo deve
inviare messaggi (o chiamare una funzione, o qualsiasi altra cosa)
ogni 1 millesimo di secondo (dopo per i controlli del  timer ne
utilizzo uno mio personale). Il problema e' proprio fare in modo che
possa effettuare i controlli.
Sperando che qualcuno abbia capito cosa intendo :P:P
Grazie
--
Messaggio di: Gordon 


Piů o meno credo di aver capito. Dubito che il messaggio WM_TIMER arrivi con
un rate di uno ogni msec. anche se nominalmente pare possibile.
Un'altra soluzione č uno thread a parte che effettui un ciclo infinito (tipo
polling) richiamando periodicamente una Sleep() di un millisecondo... non
sposta di molto il problema, ma eviti la coda dei messagi din windows, che
non offre le stesse garanzie.
Ciao. Federico.

 ogni 1 millesimo di secondo (dopo per i controlli del  timer ne
[cut]
Secondo me non è possibile e ti spiego perchè...potrei anche sbagliarmi
comunque (mi riferisco a Win 98SE, non so se le cose cambiano su altre
versioni).
L'8254 (Programmable Interval Timer) o compatibile viene impostato a non più
di 1000 interrupt al secondo (da Windows)
I servizi offerti dal kernel (per es. VTD_Begin_Min_Int_Period,
VTD_Get_Interrupt_Period, ecc...) hanno tutti una precisione di 1 ms, cioè
ritornano e accettano intervalli di tempo espressi in ms.
Inoltre, disassemblando una di quelle funzioni, mi sono accorto che Win
memorizza le frequenze dei timer virtuali (ogni utente può richiedere di
essere chiamato ogni t tempo) in una tavola fatta così:
1234567890123456.....
0000000000000000000000000000
Gli zero sono bit. Se il primo bit è 1 significa che un utente vuole essere
chiamato dopo 1 ms, ecc... Se l'n bit è uno significa insomma che almeno un
utente vuole essere chiamato dopo n ms.
Il timer (quello fisico) viene impostato all'intervallo minore. Se per
esempio nella tavola il bit più basso a valere 1 è il numero 5, il timer
verrà impostato a 5 secondi.
Questo da quello che ho visto, non ho tempo di approfondire...
[nota che sto contanto i bit partendo da 1 volutamente, così corrisponde
all'intervallo in ms.]
Questo comunque significa anche che Windows non è in grado di passare da un
thread o da un task a un altro in meno di 1 ms.
Perchè la tua funzione sia eseguita ogni millisecondo, probabilmente il tuo
programma dovrebbe essere sempre il processo corrente, in quanto se si
passasse a un altro processo ci vorrebbero almeno 2 ms per tornare al tuo (1
per andare e 1 per ritornare al tuo).
Prob.  i messaggi inviati alla tua finestra verranno eseguiti in modo
"cronologicamente scorretto": si accumuleranno in gruppi e verranno serviti
gruppo per gruppo.
Allora tanto varrebbe scegliere un intervallo di tempo maggiore (per es. 25
ms) ottenendo anzi una precisione maggiore.
La soluzione?
Agganciarsi direttamente al timer (potresti anche avere precisioni di
microsecondi) in modo da interrompere qualsiasi codice nel preciso momento
in cui il timer genera l'int.
E comunque se l'elaborazione dei dati è gravosa, sarebbe meglio bufferizzare
i dati.
Kiuhnm

Ho fatto un piccolo esperimento eseguendo i seg. due codici.
1)
for (int i = 0; i < 200; i++)
{
    Sleep(100);
}
2)
for (int i = 0; i < 20000; i++)
{
    Sleep(1);
}
Il codice 1) dura esattamente 20'', mentre il 2) ben 1' 27''!!!
Questo ovviamente significa che Sleep(1) dura più di un millisecondo
(contanto task switch, ecc...)
Kiuhnm

"gordon" </*
cgo...@genie.com
*/> ha scritto nel messaggio
news:fko3ju0coi50v3un6...@4ax.com...
: Salve, programmo con il C\C++ e le API di windows.
: utilizzo uno mio personale).
: Il problema e' proprio fare in modo che possa effettuare i controlli.
:
: Sperando che qualcuno abbia capito cosa intendo :P:P
: Grazie
Timer multimediali.
Dovresti trovare agevolmente materiale in rete o su Msdn.
susanna

 passato il tempo giusto per eseguire i controlli.
QueryPerformanceFrequency()
QueryPerformanceCounter()
Marco

 con invio di messaggi WM_TIMER.
Sicuro che il polling sia l'unica soluzione? 1 millisecondo è una frazione
di tempo troppo ridotta, questo mi fà pensare che stai cercando di risolvere
il problema in modo sbagliato. Anche se tu riuscissi a fare un controllo con
una frequenza del genere, occuperesti la CPU e non resterebbe tempo di
processo per nient'altro. Sei sicuro di non poter gestire la cosa via
eventi? Che cosa controlli di specifico?
Ciao.

polling) richiamando periodicamente una Sleep() di un millisecondo... 
si' ci avevo pensato... ma non vorrei che gestire un thread fosse
troppo dispendioso (per l'uso che ne dovrei fare)
--
Messaggio di: Gordon 

[CUT]
grazie per la tua spiegazione.
cmq si', per ora provo ad aumentare a 20 o anche 50 millesimi di
secondo... 
--
Messaggio di: Gordon 

Che cosa controlli di specifico?
controllo se e' passato tot tempo allora eseguo delle operazioni (e'
un piccolo giochino)
altrimenti niente.
--
Messaggio di: Gordon 

 altrimenti niente.
Per caso usi GetTickCount?
Kiuhnm

 altrimenti niente.
Io ti consiglierei di usare un sistema di messaggi da un thread che sta in
attesa su un handle creato da una CreateWaitableTimer(...). Tieni conto che
gestendo WM_TIMER come fai tů, qualsiasi operazione che esegui all'interno
della notifica OnTimer(...) occupa (congela) la tua applicazione finchč non
ritorni dai controlli che effettui dalle chiamate fatte all'interno di
OnTimer(...). Tieni inoltre conto che 50ms sono comunque molto pochi se usi
WM_TIMER, e tieni anche conto che la GetTickCount() di per sč ha
un'approsimazione di 55ms. Lavorare su margini di 50ms con una precisione di
55ms non č il massimo.
Ciao.

 cambiano su altre versioni).
su (questo) Windows 2000 č compresa tra 1.0032 e 10.0144 millisecondi 
[1]. Inoltre il timer piů accurato č il timer multimediale, che puň 
essere impostato al massimo in intervalli di millisecondi. Direi che 
non c'č scampo
[1] calcolati con questo programma:
program timerres;
{$APPTYPE CONSOLE}
  function NtQueryTimerResolution(
    var
      CoarsestResolution, FinestResolution, ActualResolution: Cardinal
  ): Cardinal; stdcall; external 'NTDLL.DLL';
  var
    Coarsest, Finest, Actual: Cardinal;
begin
  if NtQueryTimerResolution(Coarsest, Finest, Actual) = 0 then begin
    WriteLn('Coarsest:', Coarsest / 10000:10:5);
    WriteLn('Finest:  ',   Finest / 10000:10:5);
    WriteLn('Actual:  ',   Actual / 10000:10:5);
  end;
  ReadLn;
end.
-- 
 < 
http://www.reactos.com/
 >  Open source clone of Windows NT. Current
     Don't stand, REACT!      version 0.0.19. C, C++ and ASM developers
                              and beta testers are welcome!

 effettuare i controlli. 
*sigh* Fammi indovinare: poll di una porta hardware. Ho indovinato? se 
è così <blink>SCORDATELO</blink>. Non lo dico per cattiveria, è che 
proprio Windows <blink>NON CE LA FA</blink>. Non hai nessuna, e ripeto, 
NESSUNA garanzia che il codice venga eseguito ogni millisecondo. Usare 
un sistema operativo real-time è una soluzione. Un'altra soluzione è 
avere una periferica che solleva un interrupt ogni millisecondo e un 
driver che lo gestisca, facendo le operazioni che ti servono
(WM_TIMER comunque è in assoluto il modo peggiore. Usa Sleep la 
prossima volta)
Ah, se non fosse un poll su periferica hardware, aumenta pure il 
timeout, perchè avrai capito che se non può il tuo programma, nessun 
altro può fare granchè in un millisecondo


 possa effettuare i controlli.
Scusami, io sono ignorante di programmazione API, ma se devi fare qualcosa
di codesto genere, non vedo perche' tu debba scomodarle:
il C ha nella libreria time.h delle funzioni gia' pronte per il calcolo e
l'attesa del tempo,
e funzionano anche abbastanza bene. Non so se si puo' arrivare proprio al
millesimo
di secondo, pero' ho visto alcuni programmi che, con un ciclo infinito e un
sistema
di attese, eseguono una serie di funzioni ogni decimo o centesimo di
secondo.
Joshi

 NESSUNA garanzia che il codice venga eseguito ogni millisecondo.
Che non ci sia la garanzia sono d'accordo, ma che non ce la faccia questo è
un altro discorso. Io l'ho fatto tantissime volte, impostando un thread a
priorità più elevata (anche se non sempre era necessario) e utilizzando
QueryPerformanceCounter() per le temporizzazioni precise.
Se il programma in questione non è da redistribuire, ad esempio se viene
usato solo su un computer per un determinato scopo, io direi che potrebbe
benissimo provarci.
Marco

 non c'è scampo
Comunque si può sempre agganciare direttamente l'int del timer.
La frequenza dei click è di 1.193180 Mhz (sui PC), il contatore può assumere
valori
da 0 a FFFFh e viene decrementato ad ogni click. Quando raggiunge lo 0 l'int
viene generato e il counter viene ricaricato col valore originale (non fa
semplicemente il giro...).
In questo momento il mio counter vale 1193180 Hz / 200 Hz = 5965.9, quindi
si ha un int ogni 5 ms circa (cioè 5966 è il valore da dare al counter in
modo che tocchi lo zero 200 volte al secondo).
Insomma al massimo puoi ottenere un int ogni 0.83 *us* (non male!).
Kiuhnm

 benissimo provarci.
Ti ricordo che 1 ms è il limite massimo. Nemmeno un quantum (time-slice...)
vale così poco. Quindi perchè tutto sia preciso, non devono avvenire task
switch.
Prova a calcolare con estrema precisione (RDTSC (valore da 64 bit in
EDX:EAX)) il tempo che intercorre tra due "occorrenze" e vedrai che non è
assolutamente costante.
In Win 98, quando lo devo fare e non ho voglia di andare in ring 0,
disattivo gli int e via, ma quello non è di certo il cosiddetto "programma
in background" :-)
Altrimenti, ripeto, bisogna agganciare il timer cmos e si possono
raggiungere intervalli di 830 nanosecondi circa (1193180 Mhz).
Ciao, Kiuhnm

 troppo dispendioso (per l'uso che ne dovrei fare)
figurati. Un thread non costa quasi nulla





"gordon" </*
cgo...@genie.com
*/> a écrit dans le message news:
fko3ju0coi50v3un6...@4ax.com...

Forse questo estratto ti sara' utile:
"
5.3.5. How can I get a thread to respond in under 10 milliseconds?
Getting a user mode thread to respond to a signal even in 20mS or less on a
Win9x box is an achievement, so use of NT is the first step. Next set your
process as real time, and give the thread a high priority. Finally, play
with timeBeginPeriod to see if increasing the RTC interrupt frequency helps.
Even with all these tricks, a heavy load on the system can mean that your
thread doesn't get scheduled for tens to hundreds of milliseconds.
Locking down memory with VirtualLock helps to ensure that memory isn't paged
out, which can make response time worse. The app/user needs
SE_INC_BASE_PRIORITY_NAME rights to be able to do this. In practise it is of
little benefit. Maybe the new AllocateUserPhysicalPages() call in NT5 works
better.
"
Preso da questo link:
http://www.iseran.com/Win32/FAQ/section5.html#84
Maurus

figurati. Un thread non costa quasi nulla
davvero?
Non so' su che basi ma credevo fossero molto costosi...
allora e' una soluzione che mi piace.
--
Messaggio di: Gordon 

Per caso usi GetTickCount?
no, uso timeGetTime...
--
Messaggio di: Gordon 

 allora e' una soluzione che mi piace.
A dire il vero io ho sempre letto da qualsiasi parte che i thread sono
costosi e devono essere utilizzati solo quando "ne vale la pena" (è come
usare il quicksort per ordinare 6 numeri: è megliore il bubble sort!).
Kiuhnm

 no, uso timeGetTime...
E' un po più vecchiotta...se dovesse darti problemi su qualche versione di
Win ti consiglio di passare a GetTickCount, visto che fanno la stessa cosa.
Hai poi risolto? Hai usato 50 ms?
Kiuhnm

Hai poi risolto? Hai usato 50 ms?
per ora uso un thread che funziona molto bene (e i rallentamenti che
notavo sono scomparsi).
--
Messaggio di: Gordon 

 Non so' su che basi ma credevo fossero molto costosi...
servono giusto 1 MB di memoria libera per lo stack (ma ne vengono 
occupati solo 4 KB alla volta) e 4 KB per il TEB (dati di sistema 
associati al thread), tutto il resto esiste già. Inoltre c'è una 
piccola penalità all'avvio di ogni thread: tutte le DLL del processo 
devono essere avvisate. Ma è una cosa che generalmente richiede poco
Per andare sul sicuro, non abusarne. Nel tuo caso a cosa ti serve?


Nel tuo caso a cosa ti serve?
per effettuare vari controlli.
--
Messaggio di: Gordon 

devono essere avvisate. Ma è una cosa che generalmente richiede poco
cmq una domanda:
adesso ho risolto il problema del timer e ho aggiunto al programma
delle dialog box modless (il codice delle finestre e di apertura delle
medesime l'ho preso pari pari da un mio altro programma (scritto pochi
giorni fa') dove tutto funzionava perfettamente).
Ora pero' non funzionano :(
il compilatore mi dice (ms visual c++ 6):
***
main.cpp(787) : error C2664: 'CreateDialogParamA' : cannot convert
parameter 4 from 'int (void *,unsigned int,unsigned int,long)' to 'int
(__stdcall *)(void)'
None of the functions with this name in scope match the target type
***
questo e' il codice di apertura:
hViewDlg = CreateDialog (hInstance, TEXT ("DLG"), hwnd, ViewDlgProc);
questa e' la dialogproc:
BOOL CALLBACK ViewDlgProc (HWND hwnd, UINT message, WPARAM wParam,
LPARAM lParam);
--
Messaggio di: Gordon 


Esatto.
E per una implementazione guarda qua:
http://www.codetools.com/useritems/precisetimer.asp
Maurus

hViewDlg = CreateDialog (hInstance, TEXT ("DLG"), hwnd, ViewDlgProc);
risolto. non so perche' ma da adesso il compilatore gli gira che devo
dire (DLGPROC) ViewDlgProc ... chi capisce ms visual studio e' davvero
un genio!!
--
Messaggio di: Gordon 

"gordon" </*
cgo...@genie.com
*/> wrote in message
news:ivbeju888s191cs96...@4ax.com...

A me funzionava anche senza modifiche, comunque odio i linguaggi ad alto
livello proprio per il mostruoso utilizzo di casting al quale bisogna
rassegnarsi.
Kiuhnm

rassegnarsi.
anche a me funzionava senza modifiche ^^
si', il brutto dei linguaggi ad alto livello e' proprio il casting...
non sai mai cosa fare!!
--
Messaggio di: Gordon