Announcement

Collapse
No announcement yet.

Timer-Komponente funktioniert nicht richtig

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Timer-Komponente funktioniert nicht richtig

    Hi, ich habe das Problem, daß ich eine Hardwarekarte in einer Zeit von maximal 2 sec ansprechen muss, regelmäßig! Ich habe dafür die Timer-Komponente eingesetzt.<br>Jedoch habe ich festgestellt daß die Timer-Komponente (Interval 100) manchmal nicht innerhalb von 2 sec das OnTimerEvent auslöst.<p>Daraufhin habe ich ein Programm geschrieben nur mit einer Timerkomponente und habe mit GetTickcount die Zeit zwischen den einzelnen OnTimerEvents abgefragt. Im Durchschnitt war die Zeit bei 100 msec, jedoch wenn ein Fenster geschlossen wurde oder eine Anwendung (z.B. Groupwise-Mailsoftware) beendet wurde ist die Zeit auf das bis zu 40-fache (max 4sec) angestiegen!!!<p>Das hieße für mein richtiges Programm, daß die Hardwarekarte bei der Zeitüberschreitung aussteigt und der ganze Fertigungsprozess von vorne gestartet werden muss!!<br>Der PC (AMD K6/2 1MB Grafikonboard, Industrie PC, 128 MB RAM)<br>
    Für Tips wäre ich sehr dankbar

    Bye

  • #2
    Hi

    Versuch einen Thread zu nutzen, der mit Sleep(100) 100ms schläft.
    Ein Thread ist NICHT vom Windows Botschaften Pool abhängig, außerdem kann die Threadpriorität erhöht werden, so daß dieser Thread vom Windowssystem bevorzugt behandelt wird.

    Gruß Hagen

    <pre>

    type
    TTimeThread = class(TThread)
    procedure Execute; override;
    end;

    procedure TTimeThread.Execute;
    begin
    FreeOnTerminate := True;
    Priority := tpTimeCritical;
    while not Terminated do
    begin
    Sleep(100);
    ... hier Action, nach Möglichkeit KEIN Synchronize, bzw. SendMessage() etc.
    end;
    end;

    </pre&gt

    Comment


    • #3
      Hallo,

      das Verhalten von WM_TIMER wird von Microsoft im SDK so dokumentiert. Windows stellt Botschaften "nach Dringlichkeit" zu, wobei WM_TIMER als Schlusslicht sogar noch nach den WM_PAINT-Botschaften an der Reihe kommt. Somit treffen WM_TIMER-Botschaften nur dann ein, wenn das System nichts anderes zu tun hat.

      Wer's genauer haben möchte, muss auf die API-Funktion zum <b>Multimedia Timer</b> ausweichen oder den Vorschlag von Hagen (Thread) aufgreifen

      Comment


      • #4
        Vielen Dank Hagen, die Threadfunktion, läuft genauer als die Timer-Variante.<br>
        Jedoch habe ich in einem Beispielprogramm, daß mit GetTickCount die Zeit mißt, die zwischen den einzelnen Actionen vergangen ist, festgestellt, daß die ThreadMethode auch nicht sehr zuverlässig läuft.<br>
        Jedoch ist schon eindeutlicher Unterschied zwischen Timer und Thread zu sehen. Jedoch scheint es wenn ein Bildschirmschoner startet, daß dieser ein sehr hohe Priorität hat,da das Thread mit Sleep(100) eine Zeit von 6000 msec hat, kann das sein ?!<p>
        Andreas Kosch, wie kann ich den <b>Multimedia Timer</b> ansprechen

        Comment


        • #5
          Hi

          Ja, das KURIOSUM ist das ein Bildschirmschoner auf RING 0 !!! läuft, zumindest in Win95/98. Ring 0 ist der höchstpriveligierte "Software"-Level. Natürlich bestünde unter Win95/98 die Möglichkeit die Anwendung auf Ring 0 "hinaufzuhieven", bzw. Teile einer Anwendung im Ring 0 laufen zu lassen :-) Allerdings solltest Du erst mal

          <pre>

          SetPriorityClass(GetCurrentProcess, REALTIME_PRIORITY_CLASS);

          </pre>

          versuchen. Damit erhöhst Du die Priorität Deines Processes, und somit auch die effektive Priorität Deines Threads. Heist z.B.: ein Thread mit tpNORMAL Priority in einem Process mit REALTIME_PRIORITY_CLASS ist höher priorisiert als ein Thread mit tpTIMECRITICAL Priority in einem Process mit IDLE_PRIORITY_CLASS.
          Es besteht also ein DIREKTER Zusammenhang zwischen der Processpriorität UND der Threadpriorität !!

          Gruß Hage

          Comment


          • #6
            Hi

            Nochwas: der Multimediatimer sollte eigentlich auch nicht "mehr" bringen als ein hochpriorisierter Thread !!, da dieser MMSystem Timer auch nur auf Threads basiert, er ist also NICHT zuverlässiger, sondern NUR exakter !. Man könnte solch einen MMTimer mit einem Thread simulieren, also im Grunde den "Sleep()" Process eines Threads exakter gestalten.

            <pre>

            procedure TThreadX.Execute;
            const
            SleepExact = 100; // 100ms
            var
            T: DWord;
            begin
            T := GetTickCount + SleepExact;
            while not Terminated do
            begin
            if GetTickCount >= T then
            begin
            T := GetTickCount + SleepExact; // neuen Breakpoint
            DoAction;
            end else Sleep(SleepExact div 10); // nur Bruchteile schlafen
            end;
            end;

            </pre>

            Anstatt nun GetTickCount zu nutzen, dürfte der MMTimer intern mit den PerformanceCountern arbeiten, also mit QueryPerformanceCounter() und QueryPerformanceFrequency().

            Gruß Hagen

            PS: Letztendlich gibts es IMMER kritische Bereiche, z.B. Diskettenzugriff, die das GESAMMTE System lahmlegen !! Also auch einen Thread oder MMTimer, und sogar die interruptgesteuerte Maus versagt dann

            Comment


            • #7
              Hi, <br>
              vielen Dank, funktioniert zu 90 % besser, ausreichend für die Applikation!!<p>
              Only one problem last!!<br>
              Ich habe den Thread in eine Klasse mit eingefügt<br>
              Txxx = class()
              xxx:TTimerThread;
              end;
              Den TimerThread aktiviere ich über Resume und setzte in mit Suspend in Wartestellung!
              Jedoch wenn ich Txxx.Destroy ausführe verschwindet der Thread im Taskmanager von Windows nicht.
              Der Thread soll auch zerstört werden, unabhängig ob er gerade aktiv (Resume) oder inaktiv (Suspend) ist, ohne dabei wenn er inaktiv ist ihn wieder zu aktivieren.<br>
              Ich habe schon Terminate, Free, Destroy ausprobiert, wenn ich sie in den Destruktor der Txxx Klasse einfügt habe, kein Erfolg.<br>
              Nach mehreren Txxx.Create und Txxx.Destroy hatte ich einige Threads im Taskmanager bei meinem PRogramm stehen!!<p>

              Gruß Stepha

              Comment


              • #8
                Hallo,

                das wird so auch nicht funktionieren, denn <b>TThead</b> ist nur ein VCL-Wrapper für einen nativen Win32-Thread, der intern über die Win32-API-Funktion <b>CreateThread</b> erzeugt wird. Im Win32-API existiert zwar die Funktion <b>TerminateThread</b>, um einen Thread abzuschiessen, aber vor dem Einsatz würde ich in der SDK-Hilfe die Liste der umfangreichen Risiken und Nebenwirkungen durchlesen.

                Wenn der offizielle Web über <b>Terminate</b> nicht genutzt werden soll, ist es wohl am sinnvollsten, auf TThread zu verzichten und den Thread direkt über die API-Funktionen zu erzeugen. Beispiele für den direkten Einsatz sind in meinem Buch <i>Delphi Win32-Lösungen</i> zu finden

                Comment

                Working...
                X