Newsgroup: it.comp.lang.delphi
Titolo: Sleep non bloccante

Ciao a tutti,
mi servirebbe per una mia applicazione qualcosa di analogo alla funzione 
sleeep ma non bloccante. Ovvero non qualcosa che quando è in sleep usa 
il 100% delle risorse cpu e soprattutto che permetta le funzioni 
fondamentali, tipo il ridisegno dello schermo..
ZioGian

ZioGian ha scritto:

Application.ProcessMessages
abbinato ad un ciclo nel quale richiami l'API GetTickCount, ottieni lo 
stesso effetto di sleep, senza per quello bloccare il processo.
Ciao,
Gianluca.

 stesso effetto di sleep, senza per quello bloccare il processo.
nice ;-)
-- 
Morde. 
M-List di icld: 
http://it.groups.yahoo.com/group/icld/

 nice ;-)
;)
anche se, da come l'ho scritto si direbbe che prima fa il 
ProcessMessages e poi si mette a ciclare tanto per far passare il tempo...
In realtà sarebbe:
1. esecuzione di un ciclo dove come condizione di uscita è il 
superamento di un certo intervallo di tempo prestabilito (usando la 
funzione API GetTickCount);
2. all'interno del ciclo eseguire Application.ProcessMessages per 
permettere all'applicazione di gestire gli altri eventi in coda.
Così va meglio ;)
Naturalmente poi l'ideale sarebbe eseguire l'overload della 
Windows.sleep, aggiundo un parametro wait:Boolean dove:
- se wait vale true chiama la Windows.sleep
- se wait vale false esegue il codice di cui sopra
Il tutto, ovviamente, in una unit di uso comune memorizzata in una 
cartella da mettere in testa alle standard nel library path di Delphi.
Così sarebbe il massimo :D
Ciao,
Gianluca.


Hai fatto trenta, perche' non fare trentuno?
:-)
unit UAspettaEProcessa;
interface
uses windows, Forms;
procedure Sleep(intMillisecondi: Longint;
                booBloccante: Boolean = False); overload;
implementation
procedure Sleep(intMillisecondi: Longint;
                booBloccante: Boolean = False);
var
 intTempoiniziale, intOra: Longint;
begin
 if booBloccante
  then Windows.Sleep(intMillisecondi)
  else
   begin
    if intMillisecondi = 0 then exit;
    intTempoiniziale:=GetTickCount;
    repeat
     Application.ProcessMessages;
     intOra := GetTickCount;
    until (intOra - intTempoiniziale >= intMillisecondi)
           or (intOra < intTempoiniziale);
   end; // else
end;
end.
Ciao.
--
ACSH
[D4]
---------------------------
Chi fa da se'
fatica il doppio

ZioGian ha scritto:

La miseria..
Pensavo di aver fatto una domand idiota, invece ne è venuto fuori un 
tread abbastanza interessante..Forse addirittura abbastanza per le nuove 
FAQ..
Grazie a tutti.
ZioGian

 end.
Solo per conoscenza, ne vorrei proporre una un pò piu compatta:
"
procedure Sleep(dwMilliseconds: DWORD; Wait: Boolean = True);
var
   Start: Cardinal;
begin
   if Wait then
     Windows.Sleep(dwMilliseconds)
   else begin
     Start := GetTickCount;
     while (GetTickCount - Start) < dwMilliseconds do
       Application.ProcessMessages;
   end;
end;
"
Tieni in considerazione che, per come funziona la GetTickCount, /intOra/ 
non potrà mai essere inferiore a /intTempoIniziale/
.... Sperando che ciò ho scritto non sia stato influenzato dall'orario...
Ciao,
Gianluca.

 FAQ..
ICLD FAQ RULEZZZZZ
^______^


 Eheheheh... perchè mi piace correggere il codice degli altri ;)
In che ginepraio mi sono cacciato! 
=:-)
Appena trovo dieci minuti rileggo per bene il tuo post.
In ogni caso, che versione di Delphi usi? (giusto per 
contestualizzare un attimo).
Ciao
ACSH
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 contestualizzare un attimo).
Naturalmente il fuoco del mio post è sull'impossibilità di fare overload 
della Sleep e probabilmente per via di /stdcall/ e non certo sull'algoritmo.
Ho fatto tutta l'analisi con Delphi 6.0, poi ho provato a ricompilare 
anche in Delphi 2005 ma con lo stesso risultato.
Quando ho un attimo provo a documentarmi meglio per assicurarmi che sia 
effettivamente come penso.
Ciao,
Gianluca.

 anche in Delphi 2005 ma con lo stesso risultato.
Ho scritto la procedura ieri sera in cinque minuti e l'ho testata in meno
di 30 secondi, senza approfondire nulla, quindi qualche errore c'e' di
sicuro.
Io l'ho provata con D4 senza nessun service pack installato (sto avviando
il PC nuovo mentre quello vecchio e' in coma quasi irreversibile ...) e,
quando il code completation mi ha mostrato le due diverse possibilita', ho
dato per scontato che tutto fosse ok (superficialita', lo so).
Indaga e poi facci sapere.


ACSH ha scritto:
P.S.: ovviamente compilava ed eseguiva il tutto, of course.
;-)


 P.S.: ovviamente compilava ed eseguiva il tutto, of course.
Ahahah... anche a me. Se non avessi per caso visto l'help relativo 
all'uso dei parametri opzionali nelle funzioni overload, probabilmente 
adesso saremmo tutti felicissimi ed orgogliosi per la soluzione.... :-)
Ciao,
Gianluca.

 sull'algoritmo.
Non ho Delphi sottomano e quindi vado solo di internet.
Vedi questo estratto da un post recuperato sulla rete:
<inizio>
The declarations in Windows.pas (Delphi 7 Professional)
function GetWindowThreadProcessId(hWnd: HWND; lpdwProcessId: Pointer =
nil):
DWORD; stdcall; overload;
function GetWindowThreadProcessId(hWnd: HWND; var dwProcessId: DWORD):
DWORD; stdcall; overload;
<Fine>
Questo e' codice dalla VCL, quindi "apparentemente" corretto.
Cosa cambia rispetto al nostro codice? 
Forse la nostra Sleep va dichiarata cosi':
procedure Sleep(intMillisecondi: Longint;
booBloccante: Boolean = False); stdcall; overload;   ?
Forse sto perdendo di vista il punto centrale della discussione, e inizio
ad aver un poco di confusione in testa; per oggi pomeriggio chiudo qui (il
lavoro mi chiama), se risolvi qualcosa facci sapere.
Ciao.


Rispondo a questo livello del Thread piu che altro per comodità
Bene, sembra che sia riuscito a sbrogliare un pò la matassa. :)
O meglio: ho capito perchè *non* è possibile fare l'overload della 
Windows.Sleep.
Dall'help in linea (e potevo anche leggerlo subito) ho visto che per 
fare l'overload di procedure e funzioni è necessario che siano 
dichiarate nello stesso contesto (o nella stessa unit o "dentro" la 
stessa funzione/procedura). Inoltre *tutte* le dichiarazioni devono 
avere il modificatore /overload/.
Quindi se:
- una Sleep è dichiarata nella nostra unit (Windows_ex.pas)
- una Sleep è dichiarata nella Windows.pas, oltretutto senza /overload/
non si può fare niente.
Non pago, ho preso il sorgente della Windows.pas ed ho modificato la 
dichiarazione di Sleep aggiungendo /overload/, oltre a copiarci dentro 
la nuova Sleep, prelevata di Windows_ex.pas (alla quale ho aggiunto pure 
/stdcall/). Il problema questa volta sembra sia dato dalla direttiva 
/external/ utilizzata per importare l'API.
Quindi c'è un certo numero di fattori avversi...
Ora, perchè funzionava lo stesso?
dichiarando nella uses
"
   uses
     windows, ..., windows_ex
"
si andava a semplicemente a "sovrascrivere" la Windows.Sleep con 
Windows_ex.Sleep, quindi le chiamate, se non referenziato il nome di 
unit, andavano a quest'ultima. Basta però cambiare l'ordine delle unit 
per non riuscire nemmeno a compilare i sorgenti.
Nella Windows_ex.Sleep, effettuando la chiamata
"
   Windows.Sleep
"
si risolveva la chiamata alla sleep originale. Senza /Windows/ 
probabilmente sarebbe andata il loop.
Soluzioni:
- la piu ovvia è quella di chiamare la Sleep in un altro modo. Non 
SleepEx (che, accidenti, c'è già).
- se si vuole necessariamente mantenere il nome Sleep conviene 
commentarla (o importarla con un altro nome) in Windows.pas ed 
implementarla manualmente:
"
procedure Sleep(dwMilliseconds: DWORD; Wait: Boolean = True);
var
   Start: Cardinal;
begin
   Start := GetTickCount;
   while (GetTickCount - Start) < dwMilliseconds do
     if not Wait then
       Application.ProcessMessages;
end;
"
In questo caso varrebbe la pena di implementarla direttamente in 
Windows.pas (magari meglio usare $I): si avrebbe il vantaggio di non 
dover adattare il codice già esistente.
Ciao,
Gianluca.

prova...scusate

 prova...scusate
P L O N K !!!!!!!!
