Hallo, das Problem: im 'normalen' Programm und in einer Interruptroutine wird auf die selbe Variable zugegriffen. Wie kann man Probleme vermeiden bzw welche Suchbegriffe brauchts für Google. Danke :)
Eines der Zauberworte wäre "Interrupt Enable Flag". Semaphoren im Interrupt? Wie "synchronisiert"? Immerhin, "atomar" passt.
:
Bearbeitet durch User
A. K. schrieb: > Eines der Zauberworte wäre "Interrupt Enable Flag". woher kennst du seine Hardware, ob sie so etwas hat? > Semaphoren im Interrupt? warum nicht? > Wie "synchronisiert"? kann man erst beantworten wenn man die Hardware und Software kennt.
Peter II schrieb: > nö einRobert schrieb: > Wie kann man Probleme vermeiden Du willst mir also erzählen, dass der Einsatz des "volatile"-Schlüsselworts im gegebenen Fall keine Probleme vermeiden kann? Angenommen natürlich er nutzt C (wovon man wohl ausgehen kann).
:
Bearbeitet durch User
Dominik S. schrieb: > "volatile"-Schlüsselworts im gegebenen Fall keine Probleme vermeiden > kann? ja will ich. Volatile macht etwas komplett anders. Es ist nur ein Hinweis für den Compiler das die Variabel sind ändern kann ohne das er es "sieht". Viel mehr Probleme macht aber die Zugriff auf die Variabel wenn er nicht Atomar oder Anders abgesichert wird. Und daran ändert Volatile nicht. Wenn man weiß was man macht, kommt man auch ohne Volatile aus.
Peter II schrieb: > Wenn man weiß was man macht, kommt man auch ohne Volatile aus. Das bezweifle ich.
kopfkratz Passende Stichworte wurden ja schon genannt. Die einfachste Variante ist in der IRQ zusätzlich ein (volatile) Flag zu setzen das in der Hauptroutine anzeigt das gerade ein IRQ zugeschlagen hat und danach entscheidet wie man mit der nun durch IRQ veränderten Variable umgeht.
Daniel V. schrieb: > Das bezweifle ich. kannst du ja gerne machen. (die dümmste uns einfachste Lösung ist den optimier abzuschalten)
Peter II schrieb: > Daniel V. schrieb: >> Das bezweifle ich. > > kannst du ja gerne machen. (die dümmste uns einfachste Lösung ist den > optimier abzuschalten) und die klügste?
Peter II schrieb: >> Semaphoren im Interrupt? > warum nicht? Und was machst du in dem Interrupt, wenn die Sema schon vergeben ist? Warteschleife? Yield? ;-) Ok, es kann Szenarios geben, wo es möglich ist, im Interrupt ggf. nicht drauf zuzugreifen. Aber meistens hat man keine Wahl.
:
Bearbeitet durch User
Daniel V. schrieb: > und die klügste? die wird es nicht geben. die Abfrage in eine Funktion stecken die in einer andern C Datei liegt, oder die Funktion als noinline Kennzeichnen. Dann kann der Compiler die Variabel nicht in einem Register vorhalten. (Das sind aber mehr oder weniger hacks, um die langsamkeit beim zugriff in der ISR auf eine volatile variabel zu verhindern)
Peter II schrieb: > (Das sind aber mehr oder weniger hacks, um die langsamkeit beim zugriff > in der ISR auf eine volatile variabel zu verhindern) Wenns dir nur darum geht, dann kannst du doch die volatile variable in der ISR ins register laden und mit dem register arbeiten. was machst du mit?:
1 | volatile uint16 counter; |
2 | |
3 | ISR() |
4 | {
|
5 | |
6 | if(counter) |
7 | {
|
8 | counter--; |
9 | }
|
10 | |
11 | }
|
12 | |
13 | void main() |
14 | {
|
15 | _disable_interrupt(); |
16 | counter = 1000; |
17 | _enable_interrupt(); |
18 | while(counter); |
19 | |
20 | }
|
Peter II schrieb: > die Abfrage in eine Funktion stecken die in einer andern C Datei liegt, > oder die Funktion als noinline Kennzeichnen. > Dann kann der Compiler die Variabel nicht in einem Register vorhalten. Auf solche Ringkämpfe zwischen Programmierer und Compiler sollte man sich in produktivem Code besser nicht einlassen. Die erste Variante scheitert, wenn alles ein einem Rutsch übersetzt wird, was heute nicht mehr so selten ist. Noinline wiederum ist eine proprietäre Eigenheit vom GCC.
was machst du mit?: [/c] uint16 counter; uint16 _attribute_ ((noinline)) GetCounter() { return counter; } ISR() { if(counter) { counter--; } } void main() { _disable_interrupt(); counter = 1000; _enable_interrupt(); while( GetCounter() ); } [/c] Ich würde aber danach dem ASM code anschauen.
Bei einem 8-Bit Prozessor wirst du damit nicht glücklich. Und bei einem Prozessor mit mindestens 16 Bits ist counter = 1000; wohl stets atomar, bezogen auf den Zugriff auf counter.
:
Bearbeitet durch User
A. K. schrieb: > Bei einem 8-Bit Prozessor wirst du damit nicht glücklich. Und bei einem > Prozessor mit mindestens 16 Bits ist > counter = 1000; > wohl stets atomar. es geht ja nicht ums Atomar, sondern um das volatile. (was man also hack so einsparen kann)
Einigen wir uns einfach darauf das Peter ganz viele tolle "hacks" kennt, die man aber eigentliche nicht braucht, wenn man stattdessen einfach das - dafür vorgesehene - Schlüsselwort volatile benutzt ^^
Dominik S. schrieb: > Einigen wir uns einfach darauf das Peter ganz viele tolle "hacks" kennt, > die man aber eigentliche nicht braucht, wenn man stattdessen einfach das > - dafür vorgesehene - Schlüsselwort volatile benutzt ^^ klar kann man es auch immer so machen wie es jeder macht - nur kann man damit nicht das Optimum rausholen. Sonst würde solche schönen dinge wie http://de.wikipedia.org/wiki/Duff%E2%80%99s_Device nicht entstehen.
Peter II schrieb: > Dominik S. schrieb: >> Einigen wir uns einfach darauf das Peter ganz viele tolle "hacks" kennt, >> die man aber eigentliche nicht braucht, wenn man stattdessen einfach das >> - dafür vorgesehene - Schlüsselwort volatile benutzt ^^ > > klar kann man es auch immer so machen wie es jeder macht - nur kann man > damit nicht das Optimum rausholen. Wieso nicht? Wenn das volatile, wegen Mehrfachbenutzung der Variablen in der Schleife stört, kann man immer noch innerhalb der Schleife eine Hilfsvariable benutzen, in der man sich erst mal eine Kopie von der volatile Variablen für diesen einen Schleifendurchgang zieht. Dein 'Hack' beruht ja im Grunde auch nur darauf, dem Optimizer soviele Prügel zwischen die Beine zu werfen, so dass er diesen Teil nicht mehr optimieren kann. Ich seh da jetzt nicht wirklich einen Vorteil gegenüber volatile. Ganz im Gegenteil wurde volatile in die Sprache mit aufgenommen, eben weil derartige Hacks durch Fortschritte in den Optimizern immer unzuverlässiger wurden. > Sonst würde solche schönen dinge wie > http://de.wikipedia.org/wiki/Duff%E2%80%99s_Device nicht entstehen. Ist aber eine andere Baustelle.
Karl Heinz schrieb: > Dein 'Hack' beruht ja im Grunde auch nur darauf, dem Optimizer soviele > Prügel zwischen die Beine zu werfen, so dass er diesen Teil nicht mehr > optimieren kann. Ich seh da jetzt nicht wirklich einen Vorteil gegenüber > volatile. ich habe nur ein kleine Problem damit, das das volatile den erzeugten code in der ISR ändert, obwohl dort überhaupt kein bedarf dafür besteht und dort aber oft eine hohe Geschwindigkeit gewünscht ist. Nur weil die C leute sind nicht bessere als ein volatile einfallen lassen haben heißt das noch lange nicht das es immer die beste Lösung ist. Ich wüste auch nicht wie man es einfach und besser machen kann.
Dominik S. schrieb: > Einigen wir uns einfach darauf das Peter ganz viele tolle "hacks" kennt, > die man aber eigentliche nicht braucht, wenn man stattdessen einfach das > - dafür vorgesehene - Schlüsselwort volatile benutzt ^^ Also ... "volatile" ist nur eine Kennzeichnung für den Compiler, dass die Variable auch woanders (also nicht durch den normalen Codeablauf, z.B. in einer ISR oder einer anderen Task) geändert werden kann, und dass der Compiler die daher nicht komplett durchoptimieren (oder rauswerfen) darf. Der Zugriff von beiden Seiten muss gesichert werden, z.B. "atomic instruction", damit der upper / lower half Zugriff nicht von einem Schreibzugfriff dazwischen gestört wird. Oder - wenn es um ganze Datensätze geht, kann man mehrere Buffer (double buffering, Queue) verwenden.
Karl Heinz schrieb: > Dein 'Hack' beruht ja im Grunde auch nur darauf, dem Optimizer soviele > Prügel zwischen die Beine zu werfen, so dass er diesen Teil nicht mehr > optimieren kann. Nicht ganz. Die Zugriffe innerhalb der ISR sind optimierbar. Sein Hack erspart es, die Variable in der ISR in eine lokale Variable umzukopieren.
Dominik S. schrieb: > Einigen wir uns einfach darauf das Peter ganz viele tolle "hacks" kennt, > die man aber eigentliche nicht braucht, wenn man stattdessen einfach das > - dafür vorgesehene - Schlüsselwort volatile benutzt ^^ Nein, das ist falsch. volatile reicht nicht aus, auch wenn das hier immer gerne behauptet wird. Auf vielen uc-Plattformen mag das sogar klappen, aber allgemein ist das falsch. Eine ordentliche Synchronisation ist vonnöten. Gegebenenfalls inklusive memory barriers.
Wenn wir noch ein wenig weiter machen, dann sind wir bei Intels Transactional Memory und der Fragesteller, der vielleicht einen AVR meinte, hält uns für völlig gaga. ;-)
Peter II schrieb: > ich habe nur ein kleine Problem damit, das das volatile den erzeugten > code in der ISR ändert, obwohl dort überhaupt kein bedarf dafür besteht > und dort aber oft eine hohe Geschwindigkeit gewünscht ist. Und was ist jetzt genau das Problem daran, in der ISR einfach eine lokale nicht-volatile Variable zu verwenden?
Stefan Ernst schrieb: > Und was ist jetzt genau das Problem daran, in der ISR einfach eine > lokale nicht-volatile Variable zu verwenden? keines, es ist nur langsamer also ohne die Variable. Und man muss es wissen und machen. Man muss also wieder selber optimieren, obwohl immer gesagt wird der Compiler macht das schon.
Fred schrieb: > Nein, das ist falsch. > > volatile reicht nicht aus, auch wenn das hier immer gerne behauptet > wird. Ich habe nicht behauptet, dass "volatile" irgendwelche Probleme bezüglich nicht-atomaren Zugriffen oder Synchronisierung löst. Der TO fragte ganz oben nach Mitteln, um Probleme zu vermeiden, wenn: >im 'normalen' Programm und in einer Interruptroutine >wird auf die selbe Variable zugegriffen. Und "volatile" ist da nun mal eine der richtigen Antworten. Ich sagte nie, dass es die Lösung für alle Probleme ist. Fred schrieb: >> Einigen wir uns einfach darauf das Peter ganz viele tolle "hacks" kennt, >> die man aber eigentliche nicht braucht, wenn man stattdessen einfach das >> - dafür vorgesehene - Schlüsselwort volatile benutzt ^^ Bezog sich lediglich auf Peters Anstrengungen volatile auf alle Fälle zu vermeiden. Nicht auf das Thema Variablen im Interrupt an sich.
Peter II schrieb: > keines, es ist nur langsamer also ohne die Variable. Bitte? Da musst du mir jetzt mal erklären, was daran langsamer sein soll.
Stefan Ernst schrieb: > Peter II schrieb: >> keines, es ist nur langsamer also ohne die Variable. > > Bitte? Da musst du mir jetzt mal erklären, was daran langsamer sein > soll. glaubst du kopieren und Register gib es kostenlos in der ISR?
Peter II schrieb: > Man muss also wieder selber optimieren, obwohl immer gesagt > wird der Compiler macht das schon. Im Zweifel ist mir aber ein funktionierendes Progamm lieber, auch wenn es einen Tick langsamer ist als ein um einen Tick schnelleres Programm, welches falsche Ergebnisse bringt.
Karl Heinz schrieb: > Im Zweifel ist mir aber ein funktionierendes Progamm lieber, auch wenn > es einen Tick langsamer ist als ein um einen Tick schnelleres Programm, > welches falsche Ergebnisse bringt. und wenn es nicht funktioniert weil es zu langsam ist? Es gibt nicht immer nur eine Lösung!
Peter II schrieb: > glaubst du kopieren und Register gib es kostenlos in der ISR? Nichts von dem wird zusätzlich benötigt. In beiden Fällen wird die Variable in Register geladen. Nur dass halt einmal die Register "namenlos" sind, und im anderen Fall repräsentieren sie die lokale Variable.
Peter II schrieb: > Stefan Ernst schrieb: >> Peter II schrieb: >>> keines, es ist nur langsamer also ohne die Variable. >> >> Bitte? Da musst du mir jetzt mal erklären, was daran langsamer sein >> soll. > > glaubst du kopieren und Register gib es kostenlos in der ISR? Das Argument zieht jetzt aber nicht. Denn wenn dem Compiler in der ISR die Register ausgehen, dann muss er auch deine nicht-volatile Variable nachladen. Im Zweifel kann man immer noch mit einem nicht-volatile konstantem Pointer, welcher die Adresse der Variablen hält, das volatile innerhalb der ISR "wegcasten" und sie innerhalb der ISR damit der normalen Datenflussanalyse zuführen.
Stefan Ernst schrieb: > Peter II schrieb: >> glaubst du kopieren und Register gib es kostenlos in der ISR? > > Nichts von dem wird zusätzlich benötigt. In beiden Fällen wird die > Variable in Register geladen. Nur dass halt einmal die Register > "namenlos" sind, und im anderen Fall repräsentieren sie die lokale > Variable. kann man nicht pauschal sagen, kommt auf Hardware an. Es gibt auch Hardware die vergleiche direkt im RAM machen kann. Damit ist das kopieren zusätzliche Arbeit.
Karl Heinz schrieb: > Das Argument zieht jetzt aber nicht. > Denn wenn dem Compiler in der ISR die Register ausgehen, dann muss er > auch deine nicht-volatile Variable nachladen. bei einem Atmel ja. Aber wir haben uns noch nicht auf eine Hardware festgelegt.
Peter II schrieb: > Karl Heinz schrieb: >> Das Argument zieht jetzt aber nicht. >> Denn wenn dem Compiler in der ISR die Register ausgehen, dann muss er >> auch deine nicht-volatile Variable nachladen. > > bei einem Atmel ja. Aber wir haben uns noch nicht auf eine Hardware > festgelegt. Wir haben uns auch nicht auf einen Compiler festgelegt.
1 | uint16 _attribute_ ((noinline)) GetCounter() { |
:
Bearbeitet durch User
Peter II schrieb: > kann man nicht pauschal sagen, kommt auf Hardware an. Es gibt auch > Hardware die vergleiche direkt im RAM machen kann. Damit ist das > kopieren zusätzliche Arbeit. Zusätzlicher Code ja, zusätzliche Register evtl. ja, bei zusätzlicher Arbeit wird es komplizierter. Laden muss der Prozessor das Zeug in beiden Fällen, da es nicht der Speicher selbst ist, der den Vergleich durchführt, sondern der Prozessor. In Registern. Nur sind das ggf. temporäre unbenannte Register.
:
Bearbeitet durch User
Dominik S. schrieb: > Und "volatile" ist da nun mal eine der richtigen Antworten. Nein. volatile läßt die Race-Condition nicht verschwinden. Schau, du kannst die Augen so fest zudrücken, wie du willst. Die Realität ändert sich dadurch aber nicht.
Wenn wir mal das obige Beispiel betrachten: if(counter) counter--; Bei einer CISC wie x86/68000/M16C, also jeder Klasse von Maschinen, die mit dem Speicher direkt arbeiten können, wird bei einer volatilen Variable daraus: test counter breq ... dec counter was sich im internen Ablauf so darstellt: load temp, counter test temp breq ... load temp, counter dec temp store temp, counter Mit der Umgehung über eine lokale Variable, also unsigned t = counter; if (t) counter = t - 1; wird im Output und im Ablauf daraus das, was RISC auch macht: load r0, counter test r0 (evtl. Teil von load oder von breq) breq ... (entfällt u.U. bei ARM) dec r0 store r0 counter was zwar mehr Befehle sind, daher langsamer sein kann, aber weniger Operationen, daher schneller sein kann. Und hat ein Load weniger, was je nach Prozessor viel ausmachen kann.
:
Bearbeitet durch User
A. K. schrieb: > Und was machst du in dem Interrupt, wenn die Sema schon vergeben ist? > Warteschleife? Yield? ;-) Na klar, Yield, natürlich, was denn sonst?. Die einzige Voraussetzung, damit das funktioniert, ist, daß praktisch sämtlicher Code im System (Startup und Sleep-Kram ausgenommen, das entspricht dem Idle-Task) ebenfalls in Folge von Interrupts durchlaufen wird, also ein Timer-Interrupt als Antrieb eines Task-Schedulers agiert. Also ziemlich genau das übliche Vorgehen beim Multitasking... Und es ist auch garnicht mal so schwierig zu programmieren. Es lauft darauf hinaus, auch ISRs nach Abarbeitung ihrer exclusiv zu erledigenden Aufgaben zu einem normalen Task (wenn auch mit hoher Priorität) zu machen und ihren weiteren Ablauf der Kontrolle des Schedulers zu unterwerfen wie jeden anderen Task auch. Allerdings ist so eine Lösung als Gesamtsystem, wie jedes funktionierende MT-OS, relativ ineffizient. Bei kleinen Controllern mit nur sehr wenigen und bezüglich ihrer Aufgabe sehr überschaubaren "Tasks" durchdenkt man besser die Interaktionen detailliert und gestaltet sie so, daß die Synchronisationsmechanismen eines universellen MT-OS erst garnicht nötig werden. Welches übrigens das Problem der Notwendigkeit des Durchdenkens der möglichen Interaktionen "parallelen" Codes sowieso auch nur verringern, aber nicht überflüssig machen würde. Siehe die wohlbekannte Deadlock-Problematik. Im Kern übrigens nix anderes, als das, auf was du hinaus wolltest. Auch nur ein Deadlock. Stell' dir die Möglichkeit zur Ausführung von Code einfach abstrakt als eine durch einen Mutex geschützte Resource vor. Dann bist du unmittelbar beim ganz normalen Wahnsinn paralleler Programmierung, ganz genau entsprechend der reinen Lehre. Und natürlich entsprechend aufzulösen.
einRobert schrieb: > Wie kann man Probleme > vermeiden bzw welche Suchbegriffe brauchts für Google. Welche Probleme willst du denn vermeiden? in welcher Sprache bei welchem Compiler auf welcher Hardware? Wenn es darum einen ISR Call mit refresh der Variablen zu signalisieren reicht ein Flag. Wenn mehrfachISRs abgefangen werden sollen halt n Zähler). Das ist mega-portabel. Geht in jeder Sprache auf jeder Hardware und mit jedem compiler.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.