Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms? (https://www.delphipraxis.net/96986-dauert-sleep-1-auf-allen-windows-rechnersystemem-1ms.html)

DelphiManiac 2. Aug 2007 16:42


Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
Die Frage ist eigentlich schon im Titel erklärt.

Hintergrund ist folgender:

Ich habe eine Software die die Sleep Funktion nutzt,
diese ist auf einem anderen Rechner sehr viel langsamer (Kommunikation wird damit gesteuert),
lass ich mir die Werte (Erhöhung eines Zählers) anzeigen, dann läuft dieser wirklich um das 3 fache langsamer :wiejetzt:


Ist das so, oder hat das andere Gründe?

Gruß

r2c2 2. Aug 2007 17:04

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
Hallo,
Ein Sleep(1) heißt nur, dass mindestens eine Millisekunde gewartet wird. Was passiert ist folgednes:
- Der Main-Thread für dein Prog wird für 1ms schlafen gelegt
- Danch wacht er wieder auf
- Je nachdem, was ansonsten noch passiert, kanns aber sein, dass der Thread noch nicht gleich wieder dran kommt, weil andere Threads auch noch was arbeiten wollen

==> Es besteht nur die Garantie, dass der Thread nicht wieder aktiv wird, bevor die 1ms abgelaufen sind.

mfg

Christian

shmia 2. Aug 2007 17:09

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
Ein Sleep(1) braucht immer mehr als 1 ms, da ja im Hintergrund ein Taskwechsel stattfindet.
Es wird min. die Robin-round time slice "verbraten".
Unter 50ms muss man mit prozentual grossen Abweichungen rechnen.
Bei einem Sleep(1000) muss man mit min. 50ms Abweichung rechnen.

Christian Seehase 2. Aug 2007 19:00

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
Moin DelphiManiac,

um shmias Ausführungen noch etwas zu verdeutlichen:

Sobald Sleep aufgerufen wird, gibt der aufrufende Thread die ihm zustehende Rechenzeit ab, und bekommt erst, wenn er "turnusmässig" wieder dran ist, neue Rechenzeit zugeteilt.
Soll heissen: Selbst ein Sleep(0) hat verzögernde Wirkung.

Robert Marquardt 2. Aug 2007 20:21

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
Windows hat intern einen Heartbeat-Timer der auf deutlich mehr als 1 msec laueft. Das ist die Mindestzeit die bei Sleep(1) vergeht. Gemeinerweise kann dieser Timer auf 1 msec gestellt werden. Es kann also passieren das ploetzlich alles schneller geht (einschliesslich Treibern) nur weil ein Programm mit Miltimedia-Sachen hantiert.

DelphiManiac 2. Aug 2007 20:24

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
@all:

Ja stimmt, der Prozess (bei mir der Ganze Prozess, da es nur einen Thread gibt)
gibt seine Prozessorzeit ab und ist für min. 1 ms nicht Zuteilungsfähig,
er kann also erstwieder nach 1 ms. vom OS mit Prozessorzeit zugewiesen bekommen.

Gut, wie kann ich denn meinem Prozess eine höhere Priorität geben, bzw.
wie kann ich sicherstellen, dass mein Prozess nach 1 ms wieder aktiv wird?

Da es bei einigen Systemen sehr große unterschiede gibt, so, dass die Kommunikation auf den Systemen nicht
ordnungsgemäß läuft...

Danke euch!

jfheins 2. Aug 2007 20:28

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
Probiers doch mal damit:
Delphi-Quellcode:
for i := 0 to 100 do
asm
  NOP;
end;
:mrgreen:

Im Ernst: Wozu möchtest du unbedungt eine Pause von einer Millisekunde erzwingen??

Falls du die Kommunikation direkt beeinflussen kannst, überdenke das ganze. Wenns sowas wie n com Port ist (kenn mich da null aus) dann benutz queryperformace -counter und -frequency. In einer while-Schleife solltest du damit ein wenig Leerlauf (= Pause) erzeugen können ;)

BBG 2. Aug 2007 20:29

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
Zitat:

sicherstellen, dass mein Prozess nach 1 ms wieder aktiv wird
Nach exakt 1ms? Ich behaupte: unmöglich.

Zitat:

meinem Prozess eine höhere Priorität geben
Luckie hat dazu mal ein Tutorial geschrieben, bzw. über Threads --> guckst du hier

Luckie 2. Aug 2007 22:03

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
Verabschiede dich von deinem Konzept. Windows ist kein Echtzeitbetriebssystem. Nichts aber wirklich gar nichts kann dir garantieren, dass dein Prozess nach einer ms wieder die CPU zugeteilt bekommt, auch nicht eine höhere Priorität. Im Gegenteil, eine höhere Priorität könnte dein ganzes System instabil wwerden lassen. Wenn man der Meinung ist, dass sein Programm eine höhere Priorität benötigt, dann ist meist etwas am Design falsch. Hinzukommt, dass die kleinste mögliche Auflösung des normalen Timers bei 15 ms liegt und unter Consumer Windows bei ca. 50 ms.

Anstatt irgendwas ständig zu pollen, solltest du dich benachrichtigen lassen. Aber das sind nur Vermutungen, deswegen die Frage: Was hast du vor? Wozu brauchst du das?

DelphiManiac 3. Aug 2007 07:49

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
Nunja,

das Design meiner Kommunikationstruktur ist an der Stelle nicht ganz sauber, müsste
mit Events arbeiten und mich benachritigen lassen.

Hier geht es um ein Frage Antwort Spiel (d.h. es muss definitiv auf die Antwort (oder Timeout) gewartet werden..)

Werde das bei meinem nächsten Projekt umstellen, und werde dann mal den Quelltext posten, so
das wir hier diskutieren können wie man es optimiert.

Aber trotzdem finde ich die Abweichungen, die ich habe schon heftig,


Wie gesagt angenommen ich habe soetwas

Delphi-Quellcode:
// Ist nur ein Beispiel:
for I := 0 to 5000 do
begin
  Sleep(1);
end;
Dann dauert es auf meinem P4 ungefähr 5,5 - 6 sec

und auf einem Athlon XP 2000 mit Windows XP (frisch aufgesetzt ohne Service Pack2)
13-14 sec....

das Sleep(1) nicht genau eine ms dauert ist mir ja klar,
aber, dass sich die Abweichung so aufsummiert :?:

Gruß
DelphiManiac

SirThornberry 3. Aug 2007 08:01

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
ich hab mir für soetwas folgende Funktion geschrieben:
Delphi-Quellcode:
procedure TClassName.LoopWait(AMicroseconds: Cardinal);
var
  lCur,
  lTo  : Int64;
begin
  QueryPerformanceCounter(lTo);
  lTo := Round(lTo + fFrequency / 1000 * AMicroseconds);
  repeat
    QueryPerformanceCounter(lCur);
  until (lCur >= lTo);
end;
fFrequency wird vorher mit QueryPerformanceFrequency ermittelt.
Wobei ich grad am überlegen bin ob die "1000" da vielleicht doch falsch ist und nicht "1000 * 1000" heißen müsste. :gruebel:

alzaimar 3. Aug 2007 08:17

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
Zitat:

Zitat von DelphiManiac
Delphi-Quellcode:
for i:=1 to 5000 do
  begin
    Sleep(1);
  end;

Wieso nicht einfach
Delphi-Quellcode:
sleep(5000);

Bernhard Geyer 3. Aug 2007 08:25

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
Zitat:

Zitat von DelphiManiac
Hier geht es um ein Frage Antwort Spiel (d.h. es muss definitiv auf die Antwort (oder Timeout) gewartet werden..)

Und was spricht gegen Benachrichtigung (Events) und einen Überwachungstimer (5 Sekunden)? Du schickst deine Nachricht fort, startest den Überwachungstimer und wenn die Antwort eintrifft wird der Überwachungstimer gestopt. Alles schön in eine Komponente verpackt welche Events der Art: OnAnswer/OnTimeOut anbietet und schon kommt man der Lehre des Schichtenaufbaus nach OSI-Modell nach.

Luckie 3. Aug 2007 09:02

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
Zitat:

Zitat von DelphiManiac
Wie gesagt angenommen ich habe soetwas

Delphi-Quellcode:
// Ist nur ein Beispiel:
for I := 0 to 5000 do
begin
  Sleep(1);
end;
Dann dauert es auf meinem P4 ungefähr 5,5 - 6 sec

und auf einem Athlon XP 2000 mit Windows XP (frisch aufgesetzt ohne Service Pack2)
13-14 sec....

Da ich davon ausgehen, das beide Rechner auch unterschiedlich konfiguriert sind, wird eben auf dem anderen Rechner, deinem Prozess früher wieder CPU Zeit zugeteilt. Zu dem, und ich wiederhole mich da, ist die geringste Auflösung des normalen Timers unter Windows NT ff. 15 ms! Wie soll er da 1 ms warten können?

shmia 3. Aug 2007 09:31

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
Zitat:

Zitat von DelphiManiac
Hier geht es um ein Frage Antwort Spiel (d.h. es muss definitiv auf die Antwort (oder Timeout) gewartet werden..)

Dazu benötigt man doch keinen Sleep!!
Delphi-Quellcode:
var
   maxAntwort : double;
   Endtime : TDateTime;
   AntwortVorhanden : boolean;  // die Variable muss im private Abschnitt des Form sein
begin
   AntwortVorhanden := False;
   maxAntwort := 5.5; // Sekunden
   StelleFrage; // Frage auf Bildschirm klopfen

   Endtime := Now + maxAntwort / (60.0*60.0*24.0);
   while not AntwortVorhanden or (EndTime > Now) do
   begin
      // Ich warte !!
      Application.ProcessMessages;
      // Wenn der Benutzer eine Antwort gibt muss die Variable AntwortVorhanden auf True gesetzt werden
   end;
   if not AntwortVorhanden then
      ShowMessages('Deine Zeit ist abgelaufen!!')
   else
   begin
      // Antort prüfen
   end;

DelphiManiac 3. Aug 2007 09:42

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
@shmia


Hi, naja mit Frage Antwort Spiel habe ich eigentlich eine Kommunikation über eine Schnittstelle (USB) gemeint,
ich sende Daten raus und warte bis Daten wieder zurück kommen (Antwort)...

dann überprüfe ich sie auf Richtigkeit usw...

shmia 3. Aug 2007 09:51

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
Zitat:

Zitat von DelphiManiac
Hi, naja mit Frage Antwort Spiel habe ich eigentlich eine Kommunikation über eine Schnittstelle (USB) gemeint,
ich sende Daten raus und warte bis Daten wieder zurück kommen (Antwort)...

Warum so spät die Aufgabenbeschreibung ?
Auch dann sollte man die Systemzeit (Oder GetTimerTicks) benutzen, um den Time-Out zu berechnen.
Delphi-Quellcode:
   // Pseudocode, soll nur das Prinzip zeigen
   maxAntwort := 5.5; // Sekunden
   USB_SendMessage(....);

   Endtime := Now + maxAntwort / (60.0*60.0*24.0);
   while (EndTime > Now) and not Application.Terminated do
   begin
      if USB_ReadMessage(..) then
      begin
         // Daten sind da
         break; // Schleife verlassen
      end;
      // Alle angefallenen Event bearbeiten
      Application.ProcessMessages;
   end;

DelphiManiac 3. Aug 2007 10:29

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
Meine Klasse Kommunikation hat folgende Methode:

Delphi-Quellcode:
function TKommunikation.Communicate(Order:TOrder; Adresse:TAdress;var Data:TDaten):Integer;
{ ************************* Kommunikationsmodul ************************** }
var
  Opened:integer; // Variable die den Zustand der Verbindung zeigt
  {*** Zählervariablen: **}
  iPolling       : integer; // Variable zum Pollen der Schnittstelle
  iData          : integer; // Variable für den Abbruch, falls die Daten falsch sind
  iTimeout       : integer; // Variable für den TimeOut
  QBytes         : integer; // Anzahl der Bytes am Port
  varcheckchecksum: integer;
  varcheckcommand : integer;
  varcheckAdressH : integer;
  varcheckAdressL : integer;
  varcheckData1   : integer;
  varcheckData2   : integer;
  varcheckData3   : integer;
  varcheckData4   : integer;
  dataOk         : boolean;
  i              : integer;
  res            : DWord;
  tick           : DWORD;
  TimeOut        : DWORD;
  MilliSeconds   : DWORD;
  _time: DWORD;
  _time1: DWORD;
  time1: Cardinal;
  time2: Cardinal;
Begin
//  fCS.Enter; { Wechselseitger Ausschluss }
  //fCS.TryEnter;
//    _time:= GetTickCount;

  if NOT(Assigned(Schnittstelle)) then
  begin
    result:=300;
    exit;
  end;
  if NOT(Schnittstelle.isConnected) then
  begin
    Result:=111;
    exit;
  end;
  dataOk:=true;
  varcheckcommand:=0;
  varcheckAdressH:=0;
  varcheckAdressL:=0;
  varcheckData1:=0;
  varcheckData2:=0;
  varcheckData3:=0;
  varcheckData4:=0;
  varcheckchecksum:=0;
  QBytes:=0;
  Opened:=0;
  iData:=1;
  iTimeOut:=0; // Timeout Variable wird mit 0 initialisiert
//  Schnittstelle.FlushBufferIN; {Schnittstellenpuffer löschen}
//  Schnittstelle.FlushBufferOut; {Schnittstellenpuffer löschen}
  //****************** Befehl wird gesetzt***********************//
  //Befehl zB.: ReadWord (RW) oder (WR) WriteRequest oder (RF) ReadFloat
  case Order of
    READ_WORD:         ReadWord(Adresse.RS485Adress,Adresse.AdressHigh,Adresse.AdressLow);
    READ_BYTE:         ReadByte(Adresse.RS485Adress,Adresse.AdressHigh,Adresse.AdressLow);
//    READ_FLOAT:        ReadFloat(Adresse.RS485Adress,Adresse.AdressHigh,Adresse.AdressLow);
    WRITE_WORD:        WriteWord(Adresse.RS485Adress,Adresse.AdressHigh,Adresse.AdressLow,Data.Data1,Data.Data2);
    WRITE_BYTE:        WriteByte(Adresse.RS485Adress,Adresse.AdressHigh,Adresse.AdressLow,Data.Data2);
//    WRITE_FLOAT:       WriteFloat(Adresse.RS485Adress,Adresse.AdressHigh,Adresse.AdressLow,Data.Data1,Data.Data2,Data.Data3,Data.Data4);
//    WRITE_RESET:       WriteReset(Adresse.RS485Adress);
    WRITE_REQUEST:     WriteRequest(Adresse.RS485Adress);
  end;



  // ***********************************************************//
  repeat
    if Schnittstelle.GetQBytes >0 then
    begin
      Schnittstelle.FlushBufferIN; {Schnittstellen[eingangs]puffer löschen}
    end;
    Schnittstelle.SendBytes(7,fBufferOut); {Ausgangspuffer senden}
    iPolling:=1;
    repeat
      QBytes:=Schnittstelle.GetQBytes; // Bytes am Port
      Sleep(SLEEP_POLL_TIME); ////////////////////////////////// HIER wird gepolllt
       inc(iPolling);
    until ((QBytes =7) Or (iPolling >I_POLLING_MAX));
   if (QBytes=7) then
   begin
     Schnittstelle.ReceiveBytes(7,fBufferIn); {Schnittstelleneingang lesen}
     Result:=0;
     dataOk:=false;
     //*********** DATENÜBERPRÜFUNG************
     varcheckchecksum := Checkchecksum;
     varcheckcommand := CheckCommand;
     varcheckAdressH := CheckAdressH;
     varcheckAdressL := checkAdressL;
     //******************************************
     // Bei Schreibbefehlen muss der komplette Frame, der gesendet wurde
     // auch wieder zurückkommen
     if ((Order=WRITE_REQUEST)Or
          (Order=WRITE_RESET)Or
          (Order=WRITE_BYTE)Or
          (Order=WRITE_WORD)Or
          (Order=WRITE_FLOAT)) then
      begin
        if ((varcheckchecksum=0)
          and (varcheckcommand=0)
          and (varcheckAdressH=0)and (varcheckAdressL=0)) then
        begin
          dataOk:=true;
          inc(fCounts);
          result:=comOK; // Kommunikation i.O.
          if Assigned(fOnNewCount) then fOnNewCount(fCounts);
          exit
        end;
      end
      else
      begin
     // Bei den Lesebefehlen muss die Checksum + AdresseHigh+ AdresseLow stimmen
        If ((varcheckchecksum=0) and (varcheckcommand=0) and (varcheckAdressH=0) and (varcheckAdressL=0)) then
        begin
          dataOk:=true;
          result:=comOK; // Kommunikation i.O.
//          _time1:= GetTickCount - _time;
//         fDateiListe.Add('Polling:= '+IntToStr(iPolling));
//         fDateiListe.Add('Time:= '+IntToStr(_time1));
//         fDateiListe.SaveToFile('C:\Logdatei.txt');
//         ShowMessage( IntToHex (fbufferIn[1],2) +' '+ IntToStr(_time1));
          Data.Data1 := fBufferIn[4];
          Data.Data2 := fBufferIn[5];
          Data.Data3 := fBufferIn[6];
          Data.Data4 := fBufferIn[7];
          inc(fCounts);
 //        if Assigned(fOnNewCount) then begin fOnNewCount(fCounts); end;
          exit;
        end;
      end;
  end;
  inc(iTimeout);
until (iTimeout>=TIME_OUT_WAIT_COUNTS) Or (dataOk=False) ;
  if (iTimeout>=TIME_OUT_WAIT_COUNTS) then
  begin
    Result:=comTimeOut; // TimeOut verursacht
    if Assigned(OnTimeOut) then
    begin
      fOnTimeOut(Self);
    end;
//    MessageDlg('TimeOut', mtError, [mbOk], 0); { TODO : TimeOut MessagDlg muss noch entfernt werden }
//    Schnittstelle.Disconnect;
    exit;
  end
  else
  begin
    Result:=comBadData; // Fehler bei den angekommenen Daten
//    MessageDlg('Fehler bei den angekommenen Daten', mtError, [mbOk], 0);{ TODO : BadData MessagDlg muss noch entfernt werden }
    fCS.Leave;
  end;
End;


Es gibt folgenden ablauf:

1.Senden
2.Warten
3.Überprüfen ob 7 Bytes da sind
--> JA dann 7 Bytes lesen und auf Gültigkeit prüfen
--> Nein Counter hochzählen weiter mit 3
wenn Counter > x
dann nochmal 1 und counter2 hochzählen (also nochmal senden)
irgendwann muss abgebrochen werden (nach dem 3. mal Senden beispielsweise..)

Gruß

SirThornberry 3. Aug 2007 10:32

Re: Dauert Sleep(1) auf allen Windows /Rechnersystemem 1ms?
 
Verwende bitte die Delphi-Tags


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:28 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz