Hallo, nach mehreren Videos über deprecating volatile, habe ich diese Frage: Betrifft in erster Linie Mikrocontroller-Programmierung (AVR in C). Warum kann der Compiler nicht erkennen, daß eine Variable in der ISR geändert wird? D.h. wenn ich eine Variable zum Datenaustausch zwischen Hauptprogramm und ISR verwende, muß diese heute noch volatile sein. Der Compiler sollte das doch aber selbständig erkennen, oder kennt er das Konzept einer ISR nicht? Und laut den Videos ist selbst das Lesen/Schreiben von volatile-Variablen nicht atomar, d.h. ein 16bit-Wert auf 8-bit Systemen kann nicht korrekt verwendet werden. Wie ist da der aktuelle Stand um das (mit oder ohne volatile?) korrekt zu lösen?
Hallo, eine Variable muss volatile sein wenn sich der Wert außerhalb des Programmflusses ändert. Wie zum Bsp. in einer ISR. Wenn es im Programmfluss passiert weiß das der Compiler. Wenn es in einer ISR erfolgt, zum Bsp. durch externe Signale, dann kann das der Compiler nicht erkennen. Im dümmsten Fall optimiert er sie weg ohne volatile. Der Lesezugriff muss bei >8Bit Datentypen daraus folgend atomar geschehen. Ansonsten könnte eine ISR Ausführung zwischenzeitlich den Wert verfälschen.
:
Bearbeitet durch User
Guest schrieb: > Der Compiler sollte das doch aber selbständig erkennen, oder kennt er > das Konzept einer ISR nicht? Weil nicht gleich alles Volatile sein MUSS, was in der ISR verändert wird (zB: Switch statement). Guest schrieb: > Und laut den Videos ist selbst das Lesen/Schreiben von > volatile-Variablen nicht atomar, d.h. ein 16bit-Wert auf 8-bit Systemen > kann nicht korrekt verwendet werden. > > Wie ist da der aktuelle Stand um das (mit oder ohne volatile?) korrekt > zu lösen? Da muss der Interrupt gesperrt werden (global), meist durch Makros wie di(),de() (disable/enable Interrupt).
A. K. schrieb: >> oder kennt er das Konzept einer ISR nicht? > > So ist es. Was mich eigentlich etwas wundert. Ob die Funktion jetzt von der ISR aufgerufen wird, oder vom Hauptprogramm als Reaktion auf eine Eingabe. Entzieht sich doch beides der Kontrolle des Compilers. Wie wird der zweite Fall dann gelöst? Vorbeugend in jedes "If" reinschauen?
Guest schrieb: > Warum kann der Compiler nicht erkennen, daß eine Variable in der ISR > geändert wird? Weil er ziemlich doof ist. Von paralleler Datenverarbeitung hat er keine Ahnung. Jedenfalls solange er ein C-Compiler ist. Es gibt auch andere Programmiersprachen, die schon vom Konzept her für parallele Datenverarbeitung ausgerüstet sind. Aber diese steinalte C-Leiche kann's halt nicht. Das ist bitter, denn schon zur Zeit ihrer Entstehung gab es natürlich schon Hardware mit paraller Verarbeitung. > Der Compiler sollte das doch aber selbständig erkennen, oder kennt er > das Konzept einer ISR nicht? Nein davon weiß er tatsächlich nix. viel schlimmer: es ist in seinem Konzept absolut nicht vorgesehen. "volatile" ist nur eine Verrenkung, parallele Verarbeitung trotzdem wenigstens möglich zu machen... > Und laut den Videos ist selbst das Lesen/Schreiben von > volatile-Variablen nicht atomar, d.h. ein 16bit-Wert auf 8-bit Systemen > kann nicht korrekt verwendet werden. Das kommt ganz klar auf die Hardware an. Es gibt Systeme, da sind sogar 64Bit-RMW-Zugriffe jederzeit ohne jede weitere Maßnahme atomar. Das kann man also nicht dem Compiler anlasten. Das ist eine Eigenschaft der Hardware. Ein guter Compiler abstrahiert sowas natürlich. Aber wir reden ja von C...
Andre schrieb: > A. K. schrieb: >>> oder kennt er das Konzept einer ISR nicht? >> >> So ist es. > > Was mich eigentlich etwas wundert. Ob die Funktion jetzt von der ISR > aufgerufen wird, oder vom Hauptprogramm als Reaktion auf eine Eingabe. > Entzieht sich doch beides der Kontrolle des Compilers. > Wie wird der zweite Fall dann gelöst? Vorbeugend in jedes "If" > reinschauen? Nehmen wir vereinfachend an, dass der Compiler jede Funktion individuell übersetzt, ohne dabei Kenntnis des Codes anderer Funktionen einfliessen zu lassen. Dann wird der Compiler dafür sorgen, dass keine Variablen, auf die auch andere zugreifen können, über einen Funktionsaufruf hinweg in Registern verbleiben. Denn er weiss nicht, ob sie im Zuge des Aufrufs verändert werden. In Codesektionen ohne Funktionsaufruf hingegen geht er davon aus, dass darin ausschliesslich der darin befindliche Code läuft. Er kann diesen Code also optimieren und umbauen, ohne auf irgendwelche Funktionsaufrufe Rücksicht nehmen zu müssen, weil da (vermeintlich) keine sind. Und da liegt nun der Hase im Pfeffer, denn ein Interrupt Handler haut da mittenrein, ohne dass der Compiler dies berücksichtigt. Müsste der Compiler Interrupts berücksichtigen, müsste er auf viele wichtige Optimierungen verzichten, da der Interrupt zwischen 2 beliebigen aufeinanderfolgenden Maschinenbefehlen auftreten kann. Das wäre katastrophal, vgl. "volatile" für alle nicht-lokalen Variablen. Sollte er obendrin auch noch atomaren Zugriff sicherstellen, müsste er jeden einzelnen solchen Variablenzugriff auch noch atomar behandeln.
:
Bearbeitet durch User
Andre schrieb: > Vorbeugend in jedes "If" > reinschauen? Das macht ein Compiler im Prinzip sowieso. Aber fuer eine ISR gibt es eben keinen Weg von main() aus. leo
c-hater schrieb: > Es gibt Systeme, da sind sogar > 64Bit-RMW-Zugriffe jederzeit ohne jede weitere Maßnahme atomar. Nur in Bezug auf Interrupts, aber bei der von dir angesprochenen parallelen Datenverarbeitung wirds haarig. Nicht nur bei laxen memory consistency models. Klar kann man das abstrahieren, um es dem Programmierer zu erleichtern, aber die Effizienz geht dabei vor die Hunde. Schau dir mal an, wie RMW-Operationen, die bezüglich paralleler Ausführung atomar sind, in Core und Caches ablaufen. Da vergeht dir der Spass daran. Intel hatte das mit Haswell daher in die umgekehrte Richtung entwickelt und dem Programmierer explizit zu nutzende Techniken zur Verfügung gestellt, die parallelen Code erheblich beschleunigen können. Da werden Codestücke als konfliktfrei angenommen und ausgeführt, ohne sich um solche Probleme zu scheren. Aber so, dass bei dann doch erkanntem Konflikt das ganze Codestück anulliert wird.
:
Bearbeitet durch User
A. K. schrieb: > Klar kann man das abstrahieren, um es dem Programmierer zu erleichtern, > aber die Effizienz geht dabei vor die Hunde. Schau dir mal an, wie > RMW-Operationen, die bezüglich paralleler Ausführung atomar sind, in > Core und Caches ablaufen. Da vergeht dir der Spass daran. Dieses "Erlebnis" hatte ich vor gut einem Jahr, als wir unser Produkt mal auf einer dicken ARM Plattform (Qualcomm) gegen Intel gebenchmarkt haben. Intel macht viele memory barriers implizit, was gerade bei massiv parallelen Architekturen richtig auf die Performance geht. Beim ARM muß man das explizit hinschreiben, dafür aber nur da, wo es auch nötig ist. Am Ende skaliert der ARM-Krempel nahezu linear auf >40 cores (wir hatten 46 cores in der Maschine). Intel hingegen hat für 32 cores (mehr hatte unsere Testmaschine nicht) nur ca. die 16-fache Leistung eines Einzelcores, also um die 50% Skalierungsverlust. Schlußfolgerung: je parallelisierter die Architektur ist, desto wichtiger ist es, etwaige Sychronisationsmechanismen explizit zu machen, damit man sie nur dort nutzen muß, wo sie auch gebraucht werden.
Axel S. schrieb: > Schlußfolgerung: je parallelisierter die Architektur ist, desto > wichtiger ist es, etwaige Sychronisationsmechanismen explizit zu machen, > damit man sie nur dort nutzen muß, wo sie auch gebraucht werden. Und da punkten dann wieder Programmiersprachen, die entweder für die Anwendung passende höhere Abstraktionsebenen bieten, so dass man sich als Programmierer nicht darum kümmern muss - oder Programmiersprachen, die auf hinreichend niedrigem Niveau liegen, dass man sich als Programmierer darum kümmern kann.
c-hater schrieb: > Guest schrieb: > >> Warum kann der Compiler nicht erkennen, daß eine Variable in der ISR >> geändert wird? > > Weil er ziemlich doof ist. Der Hintergrund ist vielmehr der, daß die ISR programmatisch gar nicht aufgerufen wird. > "volatile" ist nur eine Verrenkung, > parallele Verarbeitung trotzdem wenigstens möglich zu machen... Volatile war eigentlich für HW-Register gedacht, und volatile alleine ist zur parallelen Programmierung nicht geeignet. Weswegen volatile auch nichts mit atomic zu tun hat. Man kann es übrigens auch so machen wie Free Pascal, was kein volatile kennt - weil es ALLE globalen Variablen als volatile annimmt. Das hat natürlich dann negative Konsequenzen für die Performance. Deswegen sind in C die globalen Variablen per default nicht volatile, außer bei den wenigen, wo man das tatsächlich braucht.
S. R. schrieb: > Axel S. schrieb: >> Schlußfolgerung: je parallelisierter die Architektur ist, desto >> wichtiger ist es, etwaige Sychronisationsmechanismen explizit zu machen, >> damit man sie nur dort nutzen muß, wo sie auch gebraucht werden. > > Und da punkten dann wieder Programmiersprachen, die entweder für die > Anwendung passende höhere Abstraktionsebenen bieten, so dass man sich > als Programmierer nicht darum kümmern muss - oder Programmiersprachen, > die auf hinreichend niedrigem Niveau liegen, dass man sich als > Programmierer darum kümmern kann. Was auch immer du damit sagen willst. Die von mir angesprochenen Mechanismen sind auf der Hardware-Ebene (Cache-Invalidierung über mehrere Nodes, barriers für out-of-order execution). Da kannst du programmatisch genau gar nichts dagegen tun. Es ist auch egal, ob du in Assembler oder in Java programmierst.
Danke erstmal für die Antworten. Daraus entnehme ich daß volatile für die von mir angesprochene Platform AVR in C erstmal unverzichtbar ist. Weiterhin muß ich also um den Zugriff auf >8 Bit globale Variablen atomar zu machen im Hauptprogramm vorher ein cli() und danach ein sei() schreiben, in der Hoffnung daß der Compiler hier wenigstens kein Instruction Reordering macht ;-). Und in der ISR auch erst nach dem Zugriff auf >8 Bit globale Variablen wieder Interrupts erlauben. Ich nehme an daß es auf dieser Plattform kein C-atomic gibt, da der Prozessor nicht mehr-core/multithread-fähig ist.
Guest schrieb: > Und in der ISR auch erst nach dem Zugriff auf >8 Bit globale Variablen > wieder Interrupts erlauben. Wie kommst du darauf? Guest schrieb: > Ich nehme an daß es auf dieser Plattform kein C-atomic gibt, da der > Prozessor nicht mehr-core/multithread-fähig ist. Das verstehe ich auch nicht.
Guest schrieb: > in der Hoffnung daß der Compiler hier wenigstens kein Instruction > Reordering macht ;-). Kann allerdings passieren. Also dass bei sowas wie uint16_t a = b / c; cli(); TIMER16 = a; sei(); die zeitraubende Division in den atomaren Bereich rutscht.
c-hater schrieb: > Von paralleler Datenverarbeitung hat er keine > Ahnung. Jedenfalls solange er ein C-Compiler ist. > [...] Aber diese steinalte C-Leiche kann's > halt nicht. Das ist bitter, denn schon zur Zeit ihrer Entstehung gab es > natürlich schon Hardware mit paraller Verarbeitung. Na huch, wusste gar nicht, dass stdatomic.h und threads.h überhaupt nicht existieren.
c-hater schrieb: > Weil er ziemlich doof ist. Nein, doof bist nur du, weil du nichts von Compilerentwicklung verstehst. Sie gehört zu Königsdisziplinen und würde dich daher auch maßlos überfordern. Stichworte (nicht für dich) sind z. B. Datenflussanalyse und gerichtete azyklische Graphen.
Arduino Fanboy D. schrieb: >> Und in der ISR auch erst nach dem Zugriff auf >8 Bit globale Variablen >> wieder Interrupts erlauben. > Wie kommst du darauf? Selbst mit Deklaration als volatile ist kein atomarer Zugriff auf >8 Bit Variablen auf einer 8-Bit Architektur garantiert. Und wenn ich in der ISR vorher wieder Interrupts erlaube, kann eine andere ISR die globale Variable halb gelesen/geschrieben haben, was durch Nicht-Wiederfreigeben von Interrupts verhindert wird. > Guest schrieb: >> Ich nehme an daß es auf dieser Plattform kein C-atomic gibt, da der >> Prozessor nicht mehr-core/multithread-fähig ist. > Das verstehe ich auch nicht. Meine Annahme ist, daß es kein C-Äquivalent zu C++ std::atomic für bestimmte embedded-Platformen wie AVR 8bit gibt. Wenn diese falsch ist bitte mich korrigieren.
Guest schrieb: > Und wenn ich in der ISR vorher wieder Interrupts erlaube, Ach.. Warum willst du in einer ISR überhaupt Interrupts erlauben? Meiner Ansicht nach, ist das bei deinem Kenntnisstand, ein Irrtum, daran überhaupt zu denken. Guest schrieb: > Meine Annahme ist, daß es kein C-Äquivalent zu C++ std::atomic für > bestimmte embedded-Platformen wie AVR 8bit gibt. Wenn diese falsch ist > bitte mich korrigieren. Du scheinst Google noch nicht gefunden zu haben! Nachholbedarf. Massiv! https://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html
Nop schrieb: > Man kann es übrigens auch so machen wie Free Pascal, was kein volatile > kennt - weil es ALLE globalen Variablen als volatile annimmt. Absichtlich, oder zu faul zum optimieren? Die ersten C Compiler, beispielsweise Ritchies Original oder Johnsons PCC, übersetzten den Code ziemlich direkt wie er dastand, ohne sonderlich eindrucksvolle statement-übergreifende Optimierung. Weshalb volatile auch nicht ernsthaft benötigt wurde. Als die Compiler besser wurden, weil es genug RAM dafür gab, änderte sich das und es kam volatile.
Guest schrieb: > Meine Annahme ist, daß es kein C-Äquivalent zu C++ std::atomic für > bestimmte embedded-Platformen wie AVR 8bit gibt. Wenn diese falsch ist > bitte mich korrigieren. Das liegt höchstens daran, dass die Platform zu irrelevant ist, als das irgendwer groß Zeit damit verpulvert einen halbwegs aktuellen Sprachstandard zu implementieren.
Beitrag #6033385 wurde vom Autor gelöscht.
Axel S. schrieb: > Die von mir angesprochenen Mechanismen sind auf der > Hardware-Ebene (Cache-Invalidierung über mehrere Nodes, > barriers für out-of-order execution). Da kannst du > programmatisch genau gar nichts dagegen tun. Wenn es nur um reine Hardwaremechanismen geht, dann hast du recht. Allerdings gibt es bei den meisten Architekturen auch Möglichkeiten, dort einzugreifen. Ob das nun durch Stärkung eines weichen Speichermodells (explizite Barrieren) oder Schwächung eines starken Speichermodells (optimistische Instruktionen) passiert, ist egal. Bei x86 ist da nicht so viel zu holen wie bei anderen Architekturen, weil es selbst ein starkes Speichermodell vorschreibt. Hast du ja auch geschrieben. Gilt aber nicht überall und auch nicht immer. > Es ist auch egal, ob du in Assembler oder in Java programmierst. Wenn mir die Hardware alle Probleme löst, dann ja. In der Regel tut sie das aber nicht (oder gibt mir Möglichkeiten, das Verhalten zu steuern). Und dann ist es nicht mehr egal.
Arduino Fanboy D. schrieb: > Du scheinst Google noch nicht gefunden zu haben! > Nachholbedarf. > Massiv! > > https://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html Danke für den Link, hab mal reingelesen: These macros operate via automatic manipulation of the Global Interrupt Status (I) bit of the SREG register. Exit paths from both block types are all managed automatically without the need for special considerations, i. e. the interrupt status will be restored to the same value it has been when entering the respective block. Also machen die das auch so ähnlich wie ich es manuell vorgeschlagen habe ;-)
A. K. schrieb: > Nop schrieb: >> Man kann es übrigens auch so machen wie Free Pascal, was kein volatile >> kennt - weil es ALLE globalen Variablen als volatile annimmt. > > Absichtlich, oder zu faul zum optimieren? Ersteres, da Standard-Pascal kein volatile kannte, was ja für eine Lehrsprache auch nachvollziehbar war. Wenn man das dann für hardwarenahe Programmierung nutzen können will, muß eben alles volatile sein. Der Impact ist aber kleiner als es wirkt, weil man natürlich problemlos read-modify-write mit lokalen Hilfvariablen machen kann, wo es zum Performance-Flaschenhals wird. Macht man in C ja auch, wenn man wiederholtes Lesen von volatile-Variablen in der ISR vermeiden will.
Guest schrieb: > Also machen die das auch so ähnlich wie ich es manuell vorgeschlagen > habe ;-) Was hast du vorgeschlagen?
A. K. schrieb: > Nop schrieb: >> Free Pascal, was kein volatile >> kennt - weil es ALLE globalen Variablen als volatile annimmt. > Absichtlich, oder zu faul zum optimieren? Wohl beides. Optimierung wird durchaus innerhalb von Funktionen durchgefuehrt, innerhalb eines Befehls sowieso. D.h. mehrere Variablenzugriffe koennen zu einem optimiert werden. Fuer die PC-Programmierung ist das ein guter Kompromiss. Lokale Variablen koennen ja hemmungslos wegoptimiert werden. Freepascal kompiliert ja auch fuer den AVR und ARM, I/O-Register werden dort als Variable mit absoluter Adresse definiert, die verhalten sich dann tatsaechlich volatil, ging ja auch nicht anders. Seit kurzem wurde beim FPC auch volatile eingefuehrt, aber nicht variablenbezogen wie bei C, sondern zugriffsbezogen als Compiler-Intrinsic. Das wurde wohl hauptsaechlich fuer das LLVM-Backend gemacht, wo Volatilitaet benoetigt wird.
c-hater schrieb: > Weil er ziemlich doof ist. Von paralleler Datenverarbeitung hat er keine > Ahnung. Jedenfalls solange er ein C-Compiler ist. Es gibt auch andere > Programmiersprachen, die schon vom Konzept her für parallele > Datenverarbeitung ausgerüstet sind. Aber diese steinalte C-Leiche kann's > halt nicht. Das ist bitter, denn schon zur Zeit ihrer Entstehung gab es > natürlich schon Hardware mit paraller Verarbeitung. Du verkennst offenbar, dass eine ISR nichts mit paralleler Datenverarbeitung zu tun hat. Das ist alles ganz schön seriell. Die Fälle, wo man echte parallele Abarbeitung hat (Multiprozessor, nicht superskalare ISA) deckt man durch Message-Queues ab (HW oder SW, je nach Performance). Arduino Fanboy D. schrieb: > Ach.. > Warum willst du in einer ISR überhaupt Interrupts erlauben? > Meiner Ansicht nach, ist das bei deinem Kenntnisstand, ein Irrtum, daran > überhaupt zu denken. Das ist bei komplexeren Architekturen absolut standard und auch so gewollt. Nennt sich reentrante ISR.. Zurück zu Queues oder Software-FIFOs: Mit 8 bit 'head' und 'tail'-Zählern kann man durchaus ohne cli()-Hacks atomare Kommunikation zwischen ISR und Hauptschleife implementieren (ja, und beide sind 'volatile'). Sollte man auch immer so machen, sonst brockt man sich nur eine Menge ekliger Szenarien ein.
Arduino Fanboy D. schrieb: > Guest schrieb: >> Also machen die das auch so ähnlich wie ich es manuell vorgeschlagen >> habe ;-) > Was hast du vorgeschlagen? Ich schrieb hier: Beitrag "Re: Warum kann der Compiler nicht erkennen, daß Variable in ISR geändert wird?" Weiterhin muß ich also um den Zugriff auf >8 Bit globale Variablen atomar zu machen im Hauptprogramm vorher ein cli() und danach ein sei() schreiben, in der Hoffnung daß der Compiler hier wenigstens kein Instruction Reordering macht ;-). Und die Macros machen das gleiche...
Fitzebutze schrieb: > Nennt sich reentrante ISR.. Ist mir durchaus bekannt! (auch wenn dich das jetzt etwas verblüfft) Aber sicher nichts für so herzlich kenntnisfreie/ungeübte Anfänger. Selbst hauptberufliche fassen das nur mit der spitzen Zange an.
Fitzebutze schrieb: > Zurück zu Queues oder Software-FIFOs: Mit 8 bit 'head' und > 'tail'-Zählern kann man durchaus ohne cli()-Hacks atomare Kommunikation > zwischen ISR und Hauptschleife implementieren (ja, und beide sind > 'volatile'). Sollte man auch immer so machen, sonst brockt man sich nur > eine Menge ekliger Szenarien ein. Ja, aber... wenn ich die ISR zum Beispiel ein Timer-Interrupt ist und dort ein 16bit-Sekundenzähler (z.B. Power-On-Zeit) aktualisiert wird, will man in main() auch den korrekten Wert gelesen bekommen. Sicher kann man auch das anders lösen. Ich dachte daß es mittlerweile etwas moderner geht, die Macros von <util/atomic.h> erzeugen ja atomic code blocks, keine atomic Variablen.
Guest schrieb: > im Hauptprogramm vorher ein cli() und danach ein sei() Naja... Das ist nur eine der Varianten, welche der ATOMIC_BLOCK bereit stellt, und gar nicht mal die beste, aus meiner Sicht.
Guest schrieb: > wenn ich die ISR zum Beispiel ein Timer-Interrupt ist und dort ein > 16bit-Sekundenzähler (z.B. Power-On-Zeit) aktualisiert wird, > will man in main() auch den korrekten Wert gelesen bekommen. Nimmste einfach ein sequential lock: Solange auslesen, bis zweimal nacheinander dasselbe Ergebnis vorliegt. Eine ganz simple Schleife.
c-hater schrieb: > Weil er ziemlich doof ist. Jepp, das ist die beste Anwort im Thread. Tobias schrieb: > weil du nichts von Compilerentwicklung > verstehst Ist der compiler ein Selbstzweck, oder was steckt sinnhaftig dahinter? Es ist doch Sch..egal, ob der Compilerentwickler es nicht auf die Reihe kriegt. Es müsste nicht so sein, der compiler könnte eine Warning schmeissen und gut isses. Arduino Fanboy D. schrieb: > Warum willst du in einer ISR überhaupt Interrupts erlauben? Nested Interrupts sind doch Standard??? Wen man keine Ahnung hat, einfach Fre... A. K. schrieb: > Absichtlich, oder zu faul zum optimieren? ??? Wo landendenn globale Variablen beim C compiler? (Ohne Optimierung!) ???
MaWin schrieb: >> Absichtlich, oder zu faul zum optimieren? > ??? Wo landendenn globale Variablen beim C compiler? (Ohne Optimierung!) Ob eine Variable global ist, ist eigentlich nicht der Punkt, das ist bei Mikrocontrollern nur der häufigste Fall. Entscheidend ist, ob ausserhalb des für den Compiler sichtbaren Quellcodes ein Zugriff darauf erfolgen kann. Und das ist auch bei einer lokalen Variablen möglich, indem man deren Adresse aus der Funktion rausschleust und in einer ISR oder per DMA darauf zugreift.
:
Bearbeitet durch User
MaWin schrieb: > Es müsste nicht so sein, der compiler könnte eine Warning > schmeissen und gut isses. Bahnhof. Wann sollte er welche Warnung ausgeben?
Hallo, ich denke das sucht der TO und ist sicher in der Anwendung. Verwende ich wenn ich es benötige.
1 | ATOMIC_BLOCK (ATOMIC_RESTORESTATE) { // cli()+sei() mit SREG Sicherung |
2 | {
|
3 | |
4 | }
|
A. K. schrieb: > Ob eine Variable global ist, ist eigentlich nicht der Punkt, Doch, genau das ist der gefragte Fall: Eine Variable auch in derr ISR nutzen. Und da kann der Compiler ganz einfach eine Warning absetzen.
Sollte also in einer ISR bei jedem Zugriff auf nicht dort als lokal bekannte und nicht als volatile deklarierte Daten gewarnt werden? Dafur müsste der Compiler überhaupt erst wissen, dass es eine ISR ist. Bei den Cortex M sind ISR normale Funktionen ohne besondere Eigenschaften, weshalb man sie nur dafür entsprechend attributieren müsste. Funktionen, die darin aufgerufen werden, natürlich auch. Zudem tritt das gleiche Problem auch bei Verwendung eines preemptiven RTOS auf, auch ohne parallele Threads in Hardware, und ohnehin bei jedem Programm auf einem heutigen Betriebssystem. Da ist freilich jede Funktion potentiell betroffen. Ich fürchte, da hat c-hater Recht. Das gibt C nicht her. Dafür bräuchte man eine Sprache, die z.B. ein Konzept von thread-lokalen und übergreifenden Datenräumen in die Sprache integriert.
:
Bearbeitet durch User
Arduino Fanboy D. schrieb: > Das ist nur eine der Varianten, welche der ATOMIC_BLOCK bereit stellt, > und gar nicht mal die beste, aus meiner Sicht. Kommt eben auf die konkrete Anwendung an. Das Schlimme an der Sache ist: um die korrekte Variante zu wählen, muss man halt genau wissen, was man tut. D.h.: von der Syntax-überkandidelten C-Abstraktion bleibt ein negativer Nutzeffekt. Man muss nach wie vor wissen, was die Maschine macht, zusätzlich aber diesen Syntax-Bombast bewältigen. Wo bleibt da der Nutzen einer "Hochsprache"?
c-hater schrieb: > Wo bleibt da der Nutzen einer "Hochsprache"? Wenn du den Nutzen einer Hochsprache nicht erkennst, dann ist das nichts für dich. Alternativ: Wenn dir C oder C++ nicht schmeckt, dann nimm was anderes. Ansonsten: > Gott gebe mir Gelassenheit, hinzunehmen, was nicht zu ändern ist. > Mut zu ändern, was ich ändern kann. > Und die nötige Weisheit, zwischen beidem zu unterscheiden.
c-hater schrieb: > Man muss nach wie vor wissen, was die Maschine > macht, zusätzlich aber diesen Syntax-Bombast bewältigen. Deswegen macht man das ja auch nicht so, sondern nimmt volatile plus ggf. Synchronisierungs-Mechanismen. C ist halt der beste portable Makro-Assembler der Welt.
c-hater schrieb: > Wo bleibt da der Nutzen einer "Hochsprache"? Schreibst du eigentlich auch Android-Apps direkt in Java-Bytecode?
Der Kompiler ist zu Laufzeit nicht mehr im Spiel. Wird durch einen zweiten Interrupt, bevor der Hintergrund dazu kommt, die Variable wieder auf den Vorwert gesetzt, dann kann der Hintergrund die Änderung nicht erkennen.. Besser ist in Wert von der Interruptroutine in eine Queue oder Fifo zu schreiben.
Die goldene Regel gibts nicht. Was besser ist, hängt vom Einzelfall ab.
Arduino Fanboy D. schrieb: > c-hater schrieb: >> Wo bleibt da der Nutzen einer "Hochsprache"? > > Wenn du den Nutzen einer Hochsprache nicht erkennst, dann ist das nichts > für dich. Das wissen wir schon lange, dass das nichts für ihn ist. Rätselhaft bleibt aber, warum er trotzdem meint, bei praktisch jedem Thread über C mitdiskutieren zu müssen.
Guest schrieb: > Der Compiler sollte das doch aber selbständig erkennen, oder kennt er > das Konzept einer ISR nicht? Wann ist eine ISR überhaupt eine ISR? Geh doch mal weg von der AVR-Welt. Es gibt auch vektorisierte Interrupt-Controller, in die man nur einen Zeiger auf eine Funktion in ein Register schreibt. Da ist zur Compile-Zeit ohne tieferes HW-Modell gar nicht klar, daß da überhaupt mal irgendwann irgendwass aufgerufen wird...
Man sollte auch DMA nicht ausser Acht lassen. Da ist keinerlei Code vorhanden, der dem Compiler mitteilen könnte, worauf zugegriffen wird. Verschärfend kommt hinzu, das DMA im Unterschied zu Interrupts auch innerhalb eines Befehls reingrätschen kann. Das kann Architekturen mit mehreren Speicherzugriffen in einem Befehl erwischen.
:
Bearbeitet durch User
Rolf M. schrieb: > Das wissen wir schon lange, dass das nichts für ihn ist. Rätselhaft > bleibt aber, warum er trotzdem meint, bei praktisch jedem Thread über C > mitdiskutieren zu müssen. Weil er trotz seines Hassbekenntnisses zu C sich immer noch besser auskennt als die meisten Liebhaber.
Guest schrieb: > Weiterhin muß ich also um den Zugriff auf >8 Bit globale Variablen > atomar zu machen im Hauptprogramm vorher ein cli() und danach ein sei() > schreiben, > in der Hoffnung daß der Compiler hier wenigstens kein Instruction > Reordering macht ;-). > > Und die Macros machen das gleiche... Nach etwas mehr lesen im Quellcode, sehe ich daß die Macros hier noch eine Memory Barrier eingefügt haben:
1 | static __inline__ void __iSeiParam(const uint8_t *__s) |
2 | { |
3 | sei(); |
4 | __asm__ volatile ("" ::: "memory"); |
5 | (void)__s; |
6 | } |
Damit sollte der Compiler hier kein Instruction reordering machen. Also doch besser die Macros verwenden ;-)
Ein Interrupt handler ist ja so etwas wie ein Signal handler. Eigentlich sollte man da zur Kommunikation mit dem Rest des Programms nur Objekte verwenden, die vom Typ volatile sig_atomic_t sind, oder lock-free atomics sind (siehe Abschnitt "Lock-free property" im C17-Standard). In der Praxis funktioniert üblicherweise mehr. atomics sind im Standard optional (siehe _STDC_NO_ATOMICS_). Der aktuelle SDCC unterstützt zwar volatile sig_atomic_t, aber noch keine anderen atomics.
GEKU schrieb: > Der Kompiler ist zu Laufzeit nicht mehr im Spiel. Ich weiß gar nicht, wie oft das jetzt schon gesagt wurde....und es erklärt doch alles!! Gruß Rainer
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.