Warten auf volle Sekunde in C Linux

Gast #6498228
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
}
Gast #6498256
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
#6499143
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
}
Gast #6499537
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...
#6499727
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.
Gast #6500008
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren