Hallo zusammen,
ich habe das Gefühl, dass die Funktion nanosleep() bei mir nur teilweise
funktioniert.
1
structtimespectim;
2
tim.tv_sec=0;
3
tim.tv_nsec=1000000;
4
5
nanosleep(&tim,NULL);
Ich messe die Zeit mit QueryPerformanceCounter().
Das Problem: Wähle ich für tim.tv_nsec eine Zahl < 10000000 (z.B.
100us), so ist die Deltazeit über QueryPerformanceCounter = 0. Kann mir
jemand einen Tipp geben, wie ich nanosleep() für kleinere Zeiten (z.B.
1us) nutzen kann?
Bist du dir sicher, dass die Zeitauflösung überhaupt so genau ist, wie
du dir das vorstellst? Nur weil du Timestamps mit ns-Auflösung bekommen
kannst, heißt das nicht, dass das System überhaupt mit ns-Auflösung
misst.
S. R. schrieb:> Nur weil du Timestamps mit ns-Auflösung bekommen kannst, heißt das nicht,> dass das System überhaupt mit ns-Auflösung misst.
Außerdem bedeutet es nicht, dass das System einen Prozess überhaupt für
so eine kurze Zeit schlafen legen kann. In der Regel gibt es dafür eine
gewisse mindest-Granularität.
Rolf M. schrieb:> S. R. schrieb:>> Nur weil du Timestamps mit ns-Auflösung bekommen kannst, heißt das nicht,>> dass das System überhaupt mit ns-Auflösung misst.>> Außerdem bedeutet es nicht, dass das System einen Prozess überhaupt für> so eine kurze Zeit schlafen legen kann. In der Regel gibt es dafür eine> gewisse mindest-Granularität.
er muss ja nicht zwingend schlafen, bei kurzen Zeiten darf man auch mal
aktiv warten.
Peter II schrieb:> er muss ja nicht zwingend schlafen, bei kurzen Zeiten darf man auch mal> aktiv warten.
Zumindest aus der man-Page auf meinem System lese ich eine solche Option
nicht heraus. Es steht dort allerdings, dass es sowas unter Linux früher
mal gab, es aber entfernt wurde:
1
Old behavior
2
In order to support applications requiring much more pre‐
3
cise pauses (e.g., in order to control some time-critical
4
hardware), nanosleep() would handle pauses of up to 2 ms by
5
busy waiting with microsecond precision when called from a
6
thread scheduled under a real-time policy like SCHED_FIFO
7
or SCHED_RR. This special extension was removed in kernel
8
2.5.39, hence is still present in current 2.4 kernels, but
9
not in 2.6 kernels.
Ergänzung:
Es scheint auch generell nicht vorgesehen zu sein, nanosleep per
busy-wait zu implementieren.
http://pubs.opengroup.org/onlinepubs/009695399/functions/nanosleep.html
meint:
*********************************************************************
The nanosleep() function shall cause the current thread to be
suspended from execution until either the time interval specified by
the rqtp argument has elapsed or a signal is delivered to the calling
thread, and its action is to invoke a signal-catching function or to
terminate the process.
*********************************************************************
Das findet man genau so auch in der Linux-Manage wieder. Der Thread muss
also angehalten werden. Ich vermute, dass die busy-loop-Variante auch
deshalb aus Linux wieder entfernt wurde.
Hast du die Sourcen der Library mit der nanosleep Funktion?
Mal nachschauen, ob die einfach durch 10000000 teilen und danach einen
gröber auflösende Windows Timer benutzen.
OK vielleicht gehen wir das Thema anders herum an. Wenn eine
while-Schleife alle 1us einmal durchlaufen werden soll, wie realisiere
ich so etwas auf dem PC?
ich schrieb:> OK vielleicht gehen wir das Thema anders herum an. Wenn eine> while-Schleife alle 1us einmal durchlaufen werden soll, wie realisiere> ich so etwas auf dem PC?
Ich glaub nicht, dass man auf einem PC eine Zykluszeit von 1 µs
zuverlässig hinbekommt.
ich schrieb:> Wenn eine> while-Schleife alle 1us einmal durchlaufen werden soll, wie realisiere> ich so etwas auf dem PC?
Gar nicht.
Es treten ständig Unterbrechungen und SMIs auf, die dieses knappe Timing
zerstören.
Über >10µs könnte man vielleicht mit einem RT-Kernel reden, aber 1µs ist
unrealistisch.
>Gar nicht
Festplatten, Monitore, Netzwerk... Überall werden solche Schleifen
gebraucht.
Musst halt genau so lösen. Einen Teil deines Programmes auf dem
Prozesser. Den kritischen Teil auf zusätzlicher Hardware.
ich schrieb:> OK vielleicht gehen wir das Thema anders herum an. Wenn eine> while-Schleife alle 1us einmal durchlaufen werden soll, wie realisiere> ich so etwas auf dem PC?
Es wäre gut wenn Du einmal beschreiben würdest, was Du eigentlich machen
willst. Damit ist nicht gemeint "ich will eine while-Schleife eine
Million mal pro Sekunde laufen lassen".
Welche Anforderung soll denn damit erfüllt werden, dass eine so extrem
kurze Zeitspanne dafür benötigt wird?
Noch einer schrieb:> Festplatten, Monitore, Netzwerk... Überall werden solche Schleifen> gebraucht.
Seit Jahrzehnten nicht mehr, und selbst damals war das unüblich.
Heutzutage gibt es SATA-Controller, Grafikkarten, Netzwerkkarten.
Εrnst B. schrieb:> Noch einer schrieb:>> Festplatten, Monitore, Netzwerk... Überall werden solche Schleifen>> gebraucht.>> Seit Jahrzehnten nicht mehr, und selbst damals war das unüblich.
Was? Dass die genannten Geräte einen µC enthalten, der sich darum
kümmert? Also sprich:
Noch einer schrieb:> Den kritischen Teil auf zusätzlicher Hardware.
MaWin schrieb:> Was hat das mit dem Thema zu tun?
Lies einfach nochmal das Posting, auf das Ernst geantwortet hat.
Speziell den Satz, den ich zitiert hab. Vielleicht fällt's dir dann wie
Schuppen aus den Haaren.
Rolf M. schrieb:> Lies einfach nochmal das Posting,
Ja und? Es geht hier darum Code auf dem PC auszuführen und nicht auf
irgendwelchen sekundären Controllern.
MaWin schrieb:> Rolf M. schrieb:>> Lies einfach nochmal das Posting,>> Ja und? Es geht hier darum Code auf dem PC auszuführen und nicht auf> irgendwelchen sekundären Controllern.
Es geht vermeintlich darum. Denn wirklich sinnvoll ist die Forderung,
auf einem PC etwas im Mikrosekundentakt auszuführen, wohl ziemlich
sicher nicht.
MaWin schrieb:> Rolf M. schrieb:>> Lies einfach nochmal das Posting,>> Ja und? Es geht hier darum Code auf dem PC auszuführen und nicht auf> irgendwelchen sekundären Controllern.
Und deiner Meinung nach ist "gar nicht" als Antwort besser als ein
Hinweis darauf, was man normalerweise stattdessen macht?
Auf die Frage, was ich eigentlich machen will, kann ich nur antworten,
wenn ich weiter aushole. Ein Prof. hat nach einer Vorlesung gesagt: „Sie
müssen jetzt in der Lage sein einen 8bit uC im FPGA zu realisieren.“ Ich
habe mir gedacht, einen FPGA habe ich nicht, aber dafür einen Rechner.
Bau doch zur Übung einfach einen Emulator, passt schon. C hat man in der
Uni und einen 8bit uC mit einem „hello world blink hex file“ hat doch
jeder rumliegen. Implementierung ging eigentlich locker von der Hand
(Profis würden vom Stuhl fallen, aber egal). Die LED „blinkt“ im
Emulator fröhlich vor sich hin, jedoch viel zu schnell. Lösungsansatz →
nanosleep(). Scheinbar der falsche Ansatz. Der emuliert uC sollte
halbwegs zeitlich das reale Blinken darstellen, mehr nicht. Wie macht
man soetwas richitg?
Logisch und am einfachsten wäre es doch, entweder die Taktrate im
compilierten Programm an die sich ergebende PC-emulator-taktrate
anzupassen, oder z.b. jede ms 1000Takte abzuarbeiten.
bastel_ schrieb:> Alternativ nicht schlafen, sondern hart eine echte Nanotimesource pollen> und so lange abzählen bis 10 Mikrosekunden rum sind. Ist allerdings> unschön.
Und hat das Problem, dass das Programm ja trotzdem schlafen gelegt wird,
weil durch andere Prozesse unterbrochen. Da kommt dann alles
durcheinander.
Ich würde das da vorschlagen:
Achim S. schrieb:> oder z.b. jede ms 1000Takte abzuarbeiten.
Und wenn's mal länger als ne Millisekunde gedauert hat, entsprechend
mehr Takte abarbeiten. Eine Millisekunde ist für ein
nicht-Echtzeit-Betriebssystem schon eine recht harte Anforderung, die es
nicht zuverlässig erledigen wird. Auf der anderen Seite kommt's bei ner
µC-Emulation mit blinkender virtueller LED vielleicht auch nicht auf
harte Echtzeit an.
Rolf M. schrieb:> bastel_ schrieb:>> Alternativ nicht schlafen, sondern hart eine echte Nanotimesource pollen>> und so lange abzählen bis 10 Mikrosekunden rum sind. Ist allerdings>> unschön.>> Und hat das Problem, dass das Programm ja trotzdem schlafen gelegt wird,> weil durch andere Prozesse unterbrochen. Da kommt dann alles> durcheinander.
Durcheinander ist etwas zu hoch gegriffen, da man mit der Differenz der
Timestamps arbeitet, wird durch die Unterbrechung die Verzögerung
einfach nur länger als 10 µs. Wenn das dann beim nächsten Takt wieder
einfangen will, kann man ja den Übertrag von den nächsten 10µs abziehen
(darf natürlich nicht <0 werden). Aber schöner wird's nicht ;)
LinuxCNC steuerte Schrittmotoren aus einem User-Prozess über den
Parallelport an.
Deren Lösung: Alle nicht benötigten Dienste abschalten. Während das
Programm läuft weder Maus noch Tastatur anfassen. Und beten, dass der
Jitter klein genug bleibt.
Noch einer schrieb:> LinuxCNC steuerte Schrittmotoren aus einem User-Prozess über den> Parallelport an.
Aber nicht in einem 1µs-Raster.
Auf gut echtzeitfähiger Hardware sind vielleicht knapp unter 10µs
Perioden möglich.