Forum: PC-Programmierung Warten auf volle Sekunde in C Linux


von wendelsberg (Gast)


Lesenswert?

Hallo zusammen,

wenn man auf einem AVR eine bestimmte Aktion jede Sekunde ausfuehren 
will, setzt man ja meist einen/mehrere Timer ein.

Gibt es fuer sowas unter Linux auf dem PC einen anderen Ansatz als immer 
wieder die Sekunde per Polling abzufragen?

wendelsberg

von Mikro 7. (mikro77)


Lesenswert?

man 2 poll
man 2 select
man 2 alarm

: Bearbeitet durch User
von Heiner (Gast)


Lesenswert?

Wie wäre es mit einem cronjob?

von Kleiner Test (Gast)


Lesenswert?

1
#include <stddef.h>
2
#include <stdio.h>
3
#include <inttypes.h>
4
#include <unistd.h>
5
#include <sys/time.h>
6
7
int64_t getTime()
8
{
9
  struct timeval tv;
10
  gettimeofday(&tv, NULL);
11
12
  static time_t start_sec = 0;
13
  if (start_sec == 0)
14
    start_sec = tv.tv_sec;
15
16
  return (int64_t)(tv.tv_sec - start_sec) * 1e6 + (int64_t)(tv.tv_usec);
17
}
18
19
int main()
20
{
21
  int64_t correction = 0;
22
23
  for (int64_t i = 1;; i++)
24
  {
25
    int64_t target = i * 1e6;
26
    int64_t now = getTime();
27
    int64_t delay = target - now - correction;
28
29
    usleep(delay);
30
31
    int64_t error = getTime() - target;
32
    correction += error / 10;
33
34
    printf("%0ld: %+ld\n", i, error);
35
  }
36
}

von wendelsberg (Gast)


Lesenswert?

Heiner schrieb:
> Wie wäre es mit einem cronjob?

Scheidet aus, weil dort die kleinste Einheit 1 Minute ist.

Kleiner Test schrieb:
1
int64_t delay = target - now - correction;
2
3
    usleep(delay);
In diese Richtung hatte ich auch schon ueberlegt, aber mir gedacht, dass 
es doch sowas wie ein Sekundensignal geben koennte.

Im Moment scheint mir der Weg ueber Timer der Richtige zu sein, sehe mir 
grad das Beispiel aus man 2 timer_create an. Danke an mikro77 fuer den 
Anstoss in diese Richtung.

wendelsberg

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

wendelsberg schrieb:
> sehe mir grad das Beispiel aus man 2 timer_create an

Siehe auch https://man7.org/linux/man-pages/man2/setitimer.2.html

von Rolf M. (rmagnus)


Lesenswert?

Kleiner Test schrieb:
> for (int64_t i = 1;; i++)
>   {
>     int64_t target = i * 1e6;
>     int64_t now = getTime();
>     int64_t delay = target - now - correction;
>
>     usleep(delay);

Man kann auch die realtime-Funktionen dafür verwenden, also 
clock_gettime und clock_nanosleep. Letztere hat auch den Vorteil, dass 
man auf einen absoluten Zeitpunkt warten kann, so dass man die 
"correction" nicht braucht, die eh immer nur eine begrenzte Genauigkeit 
bietet.

PS: Also ungefähr so:
1
#include <time.h>
2
#include <stdio.h>
3
4
int main()
5
{
6
    struct timespec ts;
7
8
    clock_gettime(CLOCK_MONOTONIC, &ts);
9
10
    for (;;)
11
    {
12
        printf("Sekunde...\n");
13
        ts.tv_sec++;
14
        clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL);
15
    }
16
}

: Bearbeitet durch User
von Kleiner Test (Gast)


Lesenswert?

Rolf M. schrieb:
> Man kann auch die realtime-Funktionen dafür verwenden, also
> clock_gettime und clock_nanosleep.

Vielen Dank für den Tipp. Ich wusste, es lohnt sich, ein Stückchen Code 
zu posten... ;)


Rolf M. schrieb:
> Letztere hat auch den Vorteil, dass
> man auf einen absoluten Zeitpunkt warten kann, so dass man die
> "correction" nicht braucht, die eh immer nur eine begrenzte Genauigkeit
> bietet.

Ich hab's ausprobiert. Ja, "correction" braucht man damit nicht. Aber 
die Genauigkeit bzw. Offset bzw. Jitter ist gleich. Er schwankt im 
Durchschnitt etwa 100 Mikrosekunden mit einer Periode von etwa 10 bis 20 
Sekunden, mit einigen, heftigen Ausreißern (Spitze: 70000 
Mikrosekunden).

Ansonsten finde ich es erstaunlich, wie gut man hier auch unter Last in 
einem Multitasking-System periodische Tasks einfach steuern kann. Ich 
habe noch einen andere Regel-Algorithmus für "correction" ausprobiert, 
der sich weniger durch Ausreißer stören lässt.

Was wirklich weniger Jitter bringt, ist sched_setscheduler(SCHED_FIFO). 
Das eliminiert die Ausreißer komplett und reduziert den Jitter. Aber die 
langsame Schwingung auf dem Jitter ist dennoch vorhanden.

Spannend.

Vielleicht probiere ich auch noch SCHED_DEADLINE aus. Mal sehen...

von Rolf M. (rmagnus)


Lesenswert?

Kleiner Test schrieb:
> Was wirklich weniger Jitter bringt, ist sched_setscheduler(SCHED_FIFO).
> Das eliminiert die Ausreißer komplett und reduziert den Jitter.

Ja, genau, das bringt einiges.

> Aber die langsame Schwingung auf dem Jitter ist dennoch vorhanden.
>
> Spannend.

War das mit einem RT-Kernel und hast du mal die Prio des Thread erhöht? 
Ich hab sowas noch nicht feststellen können.

von Kleiner Test (Gast)


Lesenswert?

Kein RT-Kernel, und ziemlich alte Möhre. Ich werde berichten, sobald ich 
neue Experimente gemacht habe.

von wendelsberg (Gast)


Lesenswert?

Ich habe jetzt den Vorschlag von Rolf M. umgesetzt, funktioniert 
problemlos, der Aufwand haelt sich in Grenzen, fuer mich die perfekte 
Loesung.
Genauigkeit ist dabei kein so grosses Thema, solange dabei 3600 Abfragen 
pro Stunde herauskommen. Und das klappt.
Vielen Dank fuer die Unterstuetzung, wieder was gelernt.

wendelsberg

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.