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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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:
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