Forum: PC-Programmierung Zeitverzögerung in C


von Lila Pause (Gast)


Lesenswert?

Ich möchte gerne auf einem PC eine Zeitverzögerung von n Sekunden haben, 
so kriegt man es wohl hin aber dann wartet der Rechner aktiv oder? Wie 
macht man es besser?

1
#include <stdio.h>
2
#include <time.h>
3
4
#define WARTEZEIT 5 /* Wartezeit in Sekunden */
5
6
int main()
7
{
8
  time_t start_seconds;
9
  time_t current_seconds;
10
11
  start_seconds = time (NULL);
12
  current_seconds = start_seconds;
13
  printf ("Starting seconds: %d\n", (int)start_seconds);
14
15
  while( current_seconds < start_seconds + WARTEZEIT) /* busy waiting */
16
    current_seconds = time (NULL);
17
  printf("current_seconds = %d\n%d seconds elapsed", (int)current_seconds, WARTEZEIT);
18
19
  return 0;
20
}

von Peter (Gast)


Lesenswert?

Sleep(5000);

oder bei linux muss/kann man es mit poll oder select machen.

von Rolf Magnus (Gast)


Lesenswert?

Auf POSIX-Systemen:
1
#include <unistd.h>
2
3
...
4
sleep(5);

von Lila Pause (Gast)


Lesenswert?

Das gibt es anscheinend nicht unter Windows/MinGW? :-(

von Peter (Gast)


Lesenswert?

Lila Pause schrieb:
> Das gibt es anscheinend nicht unter Windows/MinGW? :-(

glaube ich nicht.

http://msdn.microsoft.com/en-us/library/ms686298%28VS.85%29.aspx

von Lila Pause (Gast)


Lesenswert?

Also _sleep() scheint es zu geben, aber er meint trotzdem "implicit 
declaration of function", ist also wohl nicht im unistd.h drin obwohl 
dieser existiert?

von eklige Tunke (Gast)


Lesenswert?

Lila Pause schrieb:
> Das gibt es anscheinend nicht unter Windows/MinGW? :-(
Doch laut Beitrag "MinGW (CodeBlocks 8.02) : sleep()" gibt es Sleep() 
[großes S] in der windows.h.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Lila Pause schrieb:
> Das gibt es anscheinend nicht unter Windows/MinGW? :-(

Sleep() (mit großem "S") ist ein Win32-API-Funktion, deklariert in 
winbase.h

von Timmo H. (masterfx)


Lesenswert?

Und nicht vergessen Sleep erwartet die Zeit in Millisekunden. Zudem kann 
man keine kürzeren Zeiten als ~15ms erreichen (wegen Scheduler)
Also auch ein Sleep(5) braucht 15ms und nicht 5

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Es sind 10 msec, schon seit längerem nicht mehr 15.

Und die Granularität des Schedulers lässt sich reduzieren, als 
theoretisches Minimum ist dann auch 1 msec möglich.
Das geht mit der Multimediatimer-Funktion timeBeginPeriod, der wird 
als Parameter die gewünschte Schedulergranularität in msec übergeben.
Die ist in winmm.h deklariert.

von eklige Tunke (Gast)


Lesenswert?

@ Timmo H. (masterfx) && Rufus t. Firefly (rufus) (Moderator)
Das wichtigste ist wahrscheinlich, dass er, wenn ich den Beitrag oben 
jetzt richtig verstehe, würde er gern anders warten. Siehe:
Lila Pause schrieb:
> so kriegt man es wohl hin aber dann wartet der Rechner aktiv oder? Wie
> macht man es besser?
Wobei ich sagen würde, dass das da oben passt, wenn er etwas anderes 
zutun hätte. Hat er aber anscheinend nicht, darum kann er imho auch 
Sleep() nehmen.
Ansonsten bräuchte er wohl einen Software-Timer...

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Nein, Sleep() ist kein aktives Warten. Aktives Warten ist die 
Warteschleife im Anfangsposting.
Sleep() hingegen gibt die Rechenzeit an den Scheduler zurück, der sie 
daraufhin anderen Prozessen/Threads zukommen lassen kann.

von Lila Pause (Gast)


Lesenswert?

Okay, und wie mach ich das wenn ich n Sekunden lang auf ein bestimmtes 
Ereignis warten will, und wenn es innerhalb dieser Zeitspanne passiert: 
dann soll darauf reagiert werden, und wenn es nicht passiert soll die 
Rechenzeit eben den anderen Prozessen zugeteilt werden? Also so eine Art 
"bedingtes sleep()".

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Dafür gibt es die Funktionen WaitForSingleObject und 
WaitForMultipleObjects - Voraussetzung ist natürlich ein "wartbares" 
Objekt, wie z.B. ein Eventhandle.

von Lila Pause (Gast)


Lesenswert?

Ahso, nee ich bräuchts dann doch für Linux :)

Was gemacht werden soll:
Auf einem Display erscheint eine Anzeige. Der Benutzer soll nun 
innerhalb einer gewissen Zeitspanne, zum Beispiel innerhalb von drei 
Sekunden, auf diese Anzeige reagieren. Dafür drückt er auf eine Taste. 
Wenn der Tastendruck innerhalb von drei Sekunden erfolgte, gilt das als 
erfolgreiche Bestätigung, wenn nicht zählt es als ein Timeout und wäre 
sozusagen der Fehlerfall.
Hm, vielleicht kann man es doch mit busy-waiting machen, aber ist doch 
recht inelegant oder? Vielleicht einen phtread erzeugen, der auf den 
Tastendruck wartet? Bin mir grad nicht 100% sicher ob pthreads auf der 
Zielplattform verfügbar sind, d.h. vielleicht müsste ich die Bibliothek 
dafür extra hinzulinken wenn sie noch nicht da ist und möglicherweise 
ist das nicht erlaubt, weiß gerade nicht wieviel Platz auf dem 
Zielsystem man dafür bräuchte.

von Lila Pause (Gast)


Lesenswert?

Zur Entwirrung: Ich sitze gerade an einem Rechner mit Windows und MinGW, 
laufen soll das Ganze aber später auf einem Linux Rechner.

von Simon B. (nomis)


Lesenswert?

Lila Pause schrieb:
> Auf einem Display erscheint eine Anzeige. Der Benutzer soll nun
> innerhalb einer gewissen Zeitspanne, zum Beispiel innerhalb von drei
> Sekunden, auf diese Anzeige reagieren. Dafür drückt er auf eine Taste.

Reden wir hier von dem normalen Monitor und der normalen Tastatur?

Falls ja: Welches Toolkit verwendest Du zur GUI-Programmierung?

Falls nein: Über welche Schnittstellen sind Display und Tastatur 
angebunden? Bei einer seriellen Schnittstelle wäre hier ein poll() bzw. 
ein select() das Mittel der Wahl.

Viele Grüße,
        Simon

von Lila Pause (Gast)


Lesenswert?

Simon Budig schrieb:
> Reden wir hier von dem normalen Monitor und der normalen Tastatur?

Nein, der Steuerungsrechner kommuniziert über ein Bussystem mit dem 
Display und teilt diesem so die anzuzeigenden Informationen mit.

> Falls ja: Welches Toolkit verwendest Du zur GUI-Programmierung?

Auf dem Display-Rechner wird in C++ und mit Qt programmiert, nützt mir 
selbst aber nichts, ich progammiere den Steuerungsrechner und habe dort 
eben C als Programmiersprache.

> Falls nein: Über welche Schnittstellen sind Display und Tastatur
> angebunden? Bei einer seriellen Schnittstelle wäre hier ein poll() bzw.
> ein select() das Mittel der Wahl.

Im Endeffekt werden Signale über eine Art Prozessleitsystem zwischen 
beiden hin- und hergeschickt, die ich dann im Speicher (des 
Steuerungsrechners) in Form von globalen Variablen vorliegen habe.

von Lila Pause (Gast)


Lesenswert?

So, hier noch eine professionelle UML-Grafik ;)

1
              +-------------+                              +-----------+
2
              |             |                              |           |
3
              | Steuerungs- |------ starte_Testlauf ------>|  Display  |------------------------+
4
              | rechner     |                              |           |                        |
5
              |             |                              |           |                        |
6
              +-------------+                              +-----------+ <---- zeige_Button ----+
7
                     |                                           |
8
                     |                                           |
9
                     |<------------ Button gedrueckt? -----------|
10
  +------------------|                                           |
11
  |                  |                                           |
12
  |                  |                                           |
13
  +-wenn Button ---->|                                           |
14
    gedrueckt und    |                                           |
15
    weniger als 3    |                                           |
16
    Sekunden ver-    |                                           |
17
    gangen: Test=OK, |                                           |
18
    else: nicht OK   |                                           |
19
                     |---------- Testergebnis anzeigen --------->|                                           |
20
                     |                                           |---------------+
21
                     |                                           |               |
22
                     |                                           |<---Anzeige----+
23
                     |                                           |
24
                     |                                           |
25
                     |     ( ------ ggf. Wiederholung ------> )  |
26
                     |              mit anderem Signal/          |
27
                     |              Button                       |
28
                     |                                           |
29
                     |                                           |
30
                     |                                           |
31
                     |                                           |
32
                     X                                           X

von (prx) A. K. (prx)


Lesenswert?

Lila Pause schrieb:

> Zur Entwirrung: Ich sitze gerade an einem Rechner mit Windows und MinGW,
> laufen soll das Ganze aber später auf einem Linux Rechner.

Nicht die optimale Wahl. In aller Kürze:
MinGW für Verwendung vom Windows-API.
Cygwin für Verwendung vom Unix/Linux-API.

Wenn man also unter Windows entwickelt, aber eigentlich Linux meint, 
dann ist man mit Cygwin besser dran.

von sebastians (Gast)


Lesenswert?

> Im Endeffekt werden Signale über eine Art Prozessleitsystem zwischen
> beiden hin- und hergeschickt, die ich dann im Speicher (des
> Steuerungsrechners) in Form von globalen Variablen vorliegen habe.

Dann schau mal ins Handbuch deines Prozessleitsystems obs da eine 
Funktion gibt, mit der du auf Ereignisse warten kannst. Oder Callbacks 
bei Ereignissen aufrufen lassen kannst.

Wenns nichts gibt, wirst du pollen müssen. Dazu nimmst du dann sleep 
oder einen anderen Timer mit möglichst hohem Wert (um die CPU möglichst 
wenig zu belasten), aber niedrig genug für die gewünschte Reaktionszeit.

von Simon B. (nomis)


Lesenswert?

Lila Pause schrieb:
> der Steuerungsrechner kommuniziert über ein Bussystem mit dem
> Display und teilt diesem so die anzuzeigenden Informationen mit.

Ok, Du programmierst den Steuerungsrechner und der läuft letztlich mit 
Linux.

Die Information, dass der Button gedrückt wurde, kommt über ein 
"Bussystem", meine Kristallkugel sagt mir, dass der letztlich über eine 
Device-Datei in dem Linux-System repräsentiert wird, d.h. du machst 
irgendwann ein

1
bus = open ("/dev/meinbus", O_RDWR);

oder etwas vergleichbares.

Irgendwann ist der Zeitpunkt gekommen, dann müsste das etwa so aussehen:
1
#include <poll.h>
2
...
3
4
void meine_testfunktion () {
5
  struct pollfd pfd[1];
6
  unsigned char answer[40];
7
  int ret;
8
9
  ret = write (bus, "starte Testlauf\n", 16);  
10
  if (ret < 0)
11
    ;/* Fehlerbehandlung */
12
13
  /* daraufhin stellt das Display-System den Button dar */
14
15
  pfd[0].fd = bus;
16
  pfd[0].events = POLLIN;
17
18
  ret = poll (pfd, 1, 3000);
19
  /* warte max. 3s auf Daten zum Lesen bei dem "bus" Filedeskriptor */
20
21
  if (ret < 0)
22
    ;/* Fehlerbehandlung */
23
24
  if (ret == 0)
25
    ;/* Timeout ist aufgetreten, kein Buttondruck */
26
27
  if (ret > 0)
28
    {
29
30
      if (pfd[0].revents & POLLIN)
31
        {
32
          ret = read (bus, answer, 40);
33
          if (ret < 0)
34
            ;/* Fehlerbehandlung */
35
36
          if (strncmp (answer, "button wurde gedrueckt.\n", 24))
37
            ; /* behandle Buttondruck */
38
        }
39
    }
40
}

So in etwa (von der Struktur her). Natürlich ist dieser Code nur mal 
eben aus dem Kopf hingehackt und kein Stück getestet, Du solltest auf 
jeden Fall selber nachlesen, was die einzelnen Teile machen und sie auf 
deine Bedürfnisse anpassen - es ist ja eher unwahrscheinlich, dass über 
den Bus derartige Klartextmeldungen kommen  :)

Zentral für das Warten auf Input ist der poll() Systemaufruf. 
Busy-Waiting - wie du es vorschlägst - ist eine ganz schlechte Idee. Bei 
poll() wird der wartende Prozess echt schlafengelegt und aufgeweckt, 
sobald Input zum Lesen zur Verfügung steht.

Ich hoffe das hilft,
        Simon

von Simon B. (nomis)


Lesenswert?

sebastians schrieb:
> Wenns nichts gibt, wirst du pollen müssen. Dazu nimmst du dann sleep
> oder einen anderen Timer mit möglichst hohem Wert

Wenn das unter Linux läuft, dann macht man das nicht, sondern nimmt - 
wie in dem letzten Posting von mir skizziert - poll() oder select(), 
wobei ich poll() bequemer finde.

Damit kann man eine maximale Wartezeit vorgeben, wird aber sofort 
aufgeweckt, falls Daten auf einem der beobachteten Filedeskriptoren 
anliegen (man kann poll ein Array von struct pollfd's geben, dann 
überwacht der mehrere).

(das "if (strncmp...)" sollte natürlich eigentlich "if (!strncmp...)" 
heißen)

Viele Grüße,
        Simon

von Lila Pause (Gast)


Lesenswert?

Simon, vielen Dank für die Tipps, nur mit den /dev "Dateien" und 
Filedeskriptoren kann ich da nicht ran. Das Empfangsmodul für den 
Feldbus (MVB) stellt die Signale, die für die Verarbeitung benötigt 
werden, wie gesagt in Form von globalen Variablen im Speicher zur 
Verfügung. Mit diesen kann/darf/soll/muss ich operieren. Ich kann 
höchstens neue Signale definieren die dann zusätzlich in die bisher 
schon vorhandenen Telegramme eingefügt werden, aber der Datenfluss ist 
so vorgegeben und wenn ich da selbst nochmal dran rumpfusche, haut mir 
mein Chef auf die Finger ;)

von Simon B. (nomis)


Lesenswert?

Lila Pause schrieb:
> Das Empfangsmodul für den
> Feldbus (MVB) stellt die Signale, die für die Verarbeitung benötigt
> werden, wie gesagt in Form von globalen Variablen im Speicher zur
> Verfügung.

OK, dann musst Du das API dieses Empfangsmoduls (das ist Software, 
richtig?) absuchen und nach Synchronisationsmechanismen suchen. Falls 
Dir nur Busy-Waiting bleiben sollte, dann ist das API schlecht und 
sollte überdacht werden.

Läuft das Empfangsmodul als separater Thread? Oder als eigener Prozess 
der über shared Memory mit deinem Programm kommuniziert?

Viele Grüße,
        Simon

von serg (Gast)


Lesenswert?

Lila Pause schrieb:
> Das gibt es anscheinend nicht unter Windows/MinGW? :-(

Rolf Magnus schrieb:
> Auf POSIX-Systemen:#include <unistd.h>
>
>
>
> ...
>
> sleep(5);

die Funktion gibt die heiß nicht sleep(); sondern usleep();

von Rolf Magnus (Gast)


Lesenswert?

> die Funktion gibt die heiß nicht sleep(); sondern usleep();

usleep soll man nicht mehr verwenden. Das wurde in POSIX.1-2001 als 
deprecated markiert und in POSIX.1-2008 komplett entfernt.

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.