Forum: PC-Programmierung gettimeofday legt system lahm


von Michael (Gast)


Lesenswert?

Hallo zusammen,

ich möchte in einem Programm alle paar ms eine Aktion ausführen.
Dazu polle ich in einer Funktion gettimeofday und warte dann bis die 
entsprechende Zeit vergangen ist. Das geht auch alles soweit.
Jedoch funktioniert nach einiger Zeit nichts mehr, da das System 
offensichtlich überlastet ist. Offensichtlich zu viele Aufrufe von 
gettimeofday.
Nun meine Frage, wie kann ich dafür sorgen das ich das System nicht 
überlaste und dennoch in der Lage bin die ms zu zählen?

Das Ganze läuft auf Linux, hier ein Beispiel:
1
#include <iostream>
2
#include <time.h>
3
#include <sys/time.h>
4
5
using namespace std;
6
int32_t get_time(void);
7
8
int32_t ms_counter;
9
struct timeval tv;
10
long long time1, time2;
11
12
13
14
int main()
15
{
16
    ms_counter=0;
17
    int32_t lasttime=0;
18
    gettimeofday(&tv, NULL);
19
    time1 = tv.tv_sec*1000LL+tv.tv_usec/1000;
20
while(1)
21
{
22
    if(get_time()-lasttime>=1000)
23
    {
24
        lasttime=get_time();
25
        cout <<"sekunde vorbei"<<lasttime <<endl;
26
    }
27
}
28
29
30
31
    cout << "Hello world!" << endl;
32
    return 0;
33
}
34
35
int32_t get_time(void)
36
{
37
38
    gettimeofday(&tv, NULL);
39
    time2=tv.tv_sec*1000LL+tv.tv_usec/1000;
40
    long delta= time2-time1;
41
    time1=time2;
42
    ms_counter+=(int32_t)delta;
43
44
    return(ms_counter);
45
}

Vielen Dank und Grüße
Michael

von g457 (Gast)


Lesenswert?

> Nun meine Frage, wie kann ich dafür sorgen das ich das System nicht
> überlaste und dennoch in der Lage bin die ms zu zählen?

man 2 nanosleep

HTH

von Stefan F. (Gast)


Lesenswert?

Michael schrieb:
1
while(1)
2
{
3
    if(get_time()-lasttime>=1000)
4
    {
5
        lasttime=get_time();
6
        cout <<"sekunde vorbei"<<lasttime <<endl;
7
    }
8
}

Bau da mal ein delay ein:
1
#include <unistd.h>
2
...
3
4
while(1)
5
{
6
    if(get_time()-lasttime>=1000)
7
    {
8
        lasttime=get_time();
9
        cout <<"sekunde vorbei"<<lasttime <<endl;
10
    }
11
    else
12
    {
13
        usleep(100000);
14
    }
15
}


Sonst belegt dein Programm einen ganzen CPU Kern mit 100%.

Ich fürchte allerdings, dass dadurch das Problem noch nicht gelöst wird.

> Jedoch funktioniert nach einiger Zeit nichts mehr

Wie lange ist "einige Zeit"? Ich habs's ein paar Minuten laufen lassen - 
klappt.

von Daniel A. (daniel-a)


Lesenswert?

Lasse mal ein "dmesg -w" daneben laufen, und schaue ob es irgendwelche 
relevanten Fehlermeldungen gibt, z.B. CPU überhitzt, etc.

von Michael (Gast)


Lesenswert?

Vielen Dank,

usleep hilft, bei 10 us geht die CPU Zeit deutlich runter.

VG
Michael

von Dirk B. (dirkb2)


Lesenswert?

Wenn du nur alle 1000000 us etwas machen möchtest, sind 10 us Schlaf 
recht wenig.

Du kannst die Schlafzeit auch berechnen.

von Michael (Gast)


Lesenswert?

Ja, das ist schon klar. Allerdings möchte ich jede Millisekunde etwas 
tun und das da oben war nur ein Beispiel.
Zu lange kann ich auch nicht warten, da andere Programmteile noch etwas 
arbeiten müssen.
Also ist die Lösung hier eher soviel wie möglich und so wenig wie nötig.

Gruß
Michael

von DPA (Gast)


Lesenswert?

Für sowas gibt es bessere Methoden. Poll, und je nach Anforderungen 
eventuell noch Threads.
http://man7.org/linux/man-pages/man2/poll.2.html

von Toto mit Harry (Gast)


Lesenswert?

Also wenn so eine Funktion überhaupt CPU Zeit benötigt läuft was 
schief..

von Rolf M. (rmagnus)


Lesenswert?

Michael schrieb:
> Ja, das ist schon klar. Allerdings möchte ich jede Millisekunde etwas
> tun und das da oben war nur ein Beispiel.

Dann verwende clock_nanosleep. Dem kannst du auch absolute Zeiten 
vorgeben. Du ermittelst einmal am Anfang die Zeit, dann addierst du in 
jedem Zyklus eine Millisekunde dazu und wartest bis zu dem Zeitpunkt, 
der sich daraus ergibt. Damit ist die Zykluszeit immer genau 1 ms, egal 
wie viel Rechenzeit deine Funktion zwischendrin braucht (solange das 
nicht mehr als 1 ms ist, natürlich).

> Zu lange kann ich auch nicht warten, da andere Programmteile noch etwas
> arbeiten müssen.

Dann musst du die Struktur des Programms überdenken. Entweder du hast 
eine Hauptschleife, in der (blockierend) gewartet wird, bis es irgendwas 
zu tun gibt (egal ob nun durch einen Timer oder ankommende Daten oder 
Eingaben des Benutzer), nur dann aufwacht, seine Aufgaben abarbeitet und 
sich wieder schlafen legt. Oder du machst getrennte Threads, um diese 
Dinge zu entkoppeln.
Aber alle 10 µs aufzuwachen, um zu zählen, ob schon eine ms abgelaufen 
ist, ist schlechtes Design. Abgesehen davon gibt es mindest-Dauern für 
die Zeit, die nanosleep schläft und auch eine begrenzte Auflösung, je 
nach Zielsystem.

> Also ist die Lösung hier eher soviel wie möglich und so wenig wie nötig.

Nein, das ist keine sinnvolle Lösung.


Übrigens: Wenn man ein präzises Timing will, ist zu bedenken, dass 
nanosleep wie jeder Syscall durch Signale unterbrochen werden und damit 
vorzeitig zurückkehren kann. Sofern du also mit Signalen arbeitest, 
musst du das berücksichtigen.

von Danish (Gast)


Lesenswert?

Gibt es in dem "Framework" soetwas wie Timer? Ich mach solche Dinge eig. 
immer mit Qt (QTimer, wenn ich mich richtig erinnere) es müsste doch 
auch "direkt" so gehen, oder?

von Stefan F. (Gast)


Lesenswert?

Bitte bedenkt, dass der Task Scheduler jedes laufende Programm aktiv 
unterbricht und irgendwann wieder fortsetzt. Ich meine, dass das 
Umschalt-Intervall ist standardmäßig weit mehr als eine Millisekunde 
lang ist.

Auffallen wird das, sobald man mehr gleichzeitig aktive Programme als 
CPU Kerne hat.

von Andreas M. (amesser)


Lesenswert?

Wenn man in einem Linux jede Millisekunde was machen will, dann kommt 
man mit sleep, gettimeofday usw. nicht weit. Der Scheduler vom Kernel 
kann den Prozess zu jedem beliebigen Zeitpunkt für jede beliebe Zeit 
anhalten, z.b. beim Speicherauslagern, anderen Prozessen mit höherer 
Priorität sind aktiv, hohe Peripherielast.... Auch ist der 
Scheduler-Zeitschlitz üblicherweise im Bereich von 10-100ms

Für sowas braucht man einen RT Kernel und dazu gibt es dann passende RT 
Bibliotheken und Funktionen.

Ansonsten: Anständige Timings macht man mittels "poll". Dabei gibt man 
eine absolute Zeit an und übergibt eine leere Liste von 
File-Deskriptoren. Dann weis man auch gleich wieviel Zeit man zu spät 
ist, und der Prozess schläft bis zum definierten Zeitpunkt.

Mit File-Descriptoren kann man dann natürlich auch auf "events" 
reagieren.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Andreas M. schrieb:
> Wenn man in einem Linux jede Millisekunde was machen will, dann kommt
> man mit sleep, gettimeofday usw. nicht weit. Der Scheduler vom Kernel
> kann den Prozess zu jedem beliebigen Zeitpunkt für jede beliebe Zeit
> anhalten, z.b. beim Speicherauslagern, anderen Prozessen mit höherer
> Priorität sind aktiv, hohe Peripherielast.... Auch ist der
> Scheduler-Zeitschlitz üblicherweise im Bereich von 10-100ms
>
> Für sowas braucht man einen RT Kernel und dazu gibt es dann passende RT
> Bibliotheken und Funktionen.

Die oben von mir erwähnte Funktion clock_nanosleep gehört da übrigens 
dazu. Sie gehört zur librt (real time) und lässt ein sehr genaues 
Einhalten der Millisekunde zu, sofern man den Thread auf 
Realtime-Priorität stellt und den Prozess gegen Auslagerung sperrt.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.