Forum: Mikrocontroller und Digitale Elektronik Warum kann der Compiler nicht erkennen, daß Variable in ISR geändert wird?


von Guest (Gast)


Lesenswert?

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?

von (prx) A. K. (prx)


Lesenswert?

Guest schrieb:
> oder kennt er das Konzept einer ISR nicht?

So ist es.

von Veit D. (devil-elec)


Lesenswert?

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
von Teo D. (teoderix)


Lesenswert?

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

von Andre (Gast)


Lesenswert?

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?

von c-hater (Gast)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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
von leo (Gast)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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
von Axel S. (a-za-z0-9)


Lesenswert?

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.

von S. R. (svenska)


Lesenswert?

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.

von Nop (Gast)


Lesenswert?

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.

von Axel S. (a-za-z0-9)


Lesenswert?

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.

von Guest (Gast)


Lesenswert?

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.

von Einer K. (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von Jemand (Gast)


Lesenswert?

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.

von Tobias (Gast)


Lesenswert?

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.

von Guest (Gast)


Lesenswert?

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.

von Einer K. (Gast)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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.

von Jemand (Gast)


Lesenswert?

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.
von S. R. (svenska)


Lesenswert?

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.

von Guest (Gast)


Lesenswert?

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 ;-)

von Nop (Gast)


Lesenswert?

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.

von Einer K. (Gast)


Lesenswert?

Guest schrieb:
> Also machen die das auch so ähnlich wie ich es manuell vorgeschlagen
> habe ;-)
Was hast du vorgeschlagen?

von Maxe (Gast)


Lesenswert?

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.

von Fitzebutze (Gast)


Lesenswert?

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.

von Guest (Gast)


Lesenswert?

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

von Einer K. (Gast)


Lesenswert?

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.

von Guest (Gast)


Lesenswert?

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.

von Einer K. (Gast)


Lesenswert?

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.

von Nop (Gast)


Lesenswert?

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.

von MaWin (Gast)


Lesenswert?

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!) 
???

von (prx) A. K. (prx)


Lesenswert?

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
von (prx) A. K. (prx)


Lesenswert?

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?

von Veit D. (devil-elec)


Lesenswert?

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
}

von MaWin (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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
von c-hater (Gast)


Lesenswert?

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"?

von Einer K. (Gast)


Lesenswert?

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.

von Nop (Gast)


Lesenswert?

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.

von S. R. (svenska)


Lesenswert?

c-hater schrieb:
> Wo bleibt da der Nutzen einer "Hochsprache"?

Schreibst du eigentlich auch Android-Apps direkt in Java-Bytecode?

von GEKU (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

Die goldene Regel gibts nicht. Was besser ist, hängt vom Einzelfall ab.

von Rolf M. (rmagnus)


Lesenswert?

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.

von Graf von Rotz (Gast)


Lesenswert?

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

von (prx) A. K. (prx)


Lesenswert?

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
von Thomas E. (thomase)


Lesenswert?

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.

von Guest (Gast)


Lesenswert?

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 ;-)

von Philipp Klaus K. (pkk)


Lesenswert?

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.

von Rainer V. (a_zip)


Lesenswert?

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
Noch kein Account? Hier anmelden.