AVR DB - oder doch ein Compiler-Fehler?

Beitrag #7258564 wurde von einem Moderator gelöscht.
Gast #7258571
Lesenswert?

Mich erinnert die Diskussion an Kurt Bindl.
1. Ein Priester, der meint den heiligen Gral, oder so, gefunden zu 
haben.
2. Alle anderen sind doof
3. Zeigt nichts, keine einziger Nachweis wird geführt
4. Gegenanzeigen werden komplett ausgeblendet, z.B. hier Portabilität
Gast #7258582
Lesenswert?

Für Dich gilt das Gleiche. Bleib beim Thema.
Wer portablen Code braucht soll C oder was anderes nehmen.
Lt. Aussage von Wilhelm M. bestehen angeblich keinerlei Einschränkungen.
Dann kann er Euch bestimmt auch weiterhelfen.
#7258870
Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>> Das kann man genauso natürlich auch in C / C++ machen. Dazu benötigst Du
>> kein ASM. Und in C++ kann man das natürlich auch elegant kapseln und
>> elegant erweitern. Wie das geht, schreibe ich natürlich nicht, lieber
>> Ralph ;-)
>
> Ja. Vermutlich ist es noch komplizierter und ziemlich unansehnlich.
> Wenn ich dagegen die wenigen Zeilen Asm Code stelle mit denen ich eine
> große Anzahl Zähler verwalten kann dürfte das ziemlich blamabel für C
> ausfallen.

Wohl kaum. Ich bevorzuge Code, der deterministisch arbeitet, was bei 
Deinem Geschwafel nicht der Fall ist.

> Immerhin, Punkt für Dich, kannst Du immer noch mit "Portabilität"
> protzen. Nur muß man die erstens wirklich benötigen und zweitens geht
> die eben aufs Konto von Leistung und Codetransparenz- und das behaupte
> ich bis zum Beweis des Gegenteils.

Eben nicht, wenn man es richtig macht.

> Wilhelm M. schrieb:
>> Im Gegensatz zu Dir habe ich oben sehr detailliert für den TO
>> und andere erläutert, wo das Problem ist.
>
> Deine Begründung warum es nicht besser sein soll die Sekunden des TO
> gleich in der ISR zu zählen steht bis zur aktuellen Sekunde aus. Du
> redest um den heißen Brei und versuchst den Anschein zu erwecken, daß
> diese Lösung nur mit C-Code zu belegen wäre. Ziemlich albern.

Was nicht stimmt. Ich habe oben gesagt, dass es in ASM genauso trivial 
ist wie in C / C++, wenn man es richtig macht. Um das zu widerledegn, 
müsstest Du schon mal Deinen nicht existenten Code zeigen.


> Wilhelm M. schrieb:
>> allerdings einfach nur einen
>> uint32_t Zähler hast und daraus per Shift den entsprechenden
>> quantisierten Zähler als uint8_t (atomar) für Deine Task ableitest.
>> verständliche Worte
>
> Verständliche Worte sind eher Deinen Schilderungen aus abstrakter
> Theorie anzuraten.

Mit was hast denn ein Problem? Weißt Du nicht, was atomar ist?
Gast #7258932
Lesenswert?

Zur Debatte stand meine Forderung, Sekunden statt in Main gleich nach 
Ablauf der 1000ms in der ISR zu zählen um jedem Problem mit gemeinsam 
genutzen Variablen inklusive den nötigen Interruptsperrungen aus dem 
Wege zu gehen.
Wenn DU diese simple Idee nur mit entsprechendem Code nachvollziehen 
kannst tust Du mir als angeblich so erfahrener C Experte wirklich leid.
Wer nach eigener Definition alles richtig macht mit dem besteht eher 
kein weiterer Diskussionsbedarf. Wofür ich mich aber bedanken möchte ist 
die unfreiwillige Offenbarung einiger weiterer Beschränkungen mit denen 
man beim Umstieg auf C rechnen müsste. Allen gegenteiligen Bemühungen 
inklusive vieler Nebelkerzen zum Trotz. Da musst Du noch etwas am 
Determinismus Deiner Argumentationskette arbeiten :)
#7258935
Lesenswert?

Ralf schrieb:
> Zur Debatte stand meine Forderung, Sekunden statt in Main gleich nach
> Ablauf der 1000ms in der ISR zu zählen um jedem Problem mit gemeinsam
> genutzen Variablen inklusive den nötigen Interruptsperrungen aus dem
> Wege zu gehen.

Nö, mittlerweile steht Dein Zauber-Code aka Geschwafel zur Diskussion, 
beliebige Intervalle abbilden zu können und diese in der main-loop zu 
verwenden.

> Wenn DU diese simple Idee nur mit entsprechendem Code nachvollziehen
> kannst tust Du mir als angeblich so erfahrener C Experte wirklich leid.

Ich kann nicht nur das, sondern ich kann auch noch Deinem Geschwafel 
entlocken, das es nicht funktioniert.

> Da musst Du noch etwas am
> Determinismus Deiner Argumentationskette arbeiten :)

Und Du musst Dir irgendwo noch etwas Code klauen, den Du hier zeugen 
kannst.
Gast #7258961
Lesenswert?

Leeres Geschwätz Wilhelm M.
Was ich mich aber frage, weshalb investiert hier jemand Zeit mit 
persönlichen Angriffen von dem man meinen könnte er hätte sinnvolleres 
zu tun? Irgendwas kann da wohl nicht stimmen. Frustrieren die 
Möglichkeiten anderer Sprachen? Was ist es was Dich deprimiert?
Gast #7259016
Lesenswert?

Εrnst B. schrieb:
> Andererseits ist es ja ganz gut, dass Ralph keinen Code postet.
> Sonst könnte noch jemand versucht sein, das zu kopieren...

Unbedingt.
Eine simple Idee ist ohnehin besser in Worten beschrieben.
Dann versteht sie nämlich jeder. Oder tappst Du ohne Code
so wie Wilhelm M. auch noch im Dunklen?
Gast #7259102
Lesenswert?

Wilhelm M. schrieb:
> Εrnst B. schrieb:
>
>> Gibt Bonuspunkte für Selbstreflektion.
>
> Ich denke, dass er dazu nicht fähig ist.
>
> Er hat keinen Code, den er zeigen kann. Er weiß auch gerade nicht, wo er
> sowas kopieren soll. Alles nur Gelaber.

Mach was Sinnvolleres Wilhelm M. anstatt Dir hier ständig was aus den 
Fingern zu saugen. Code gibts keinen, es langt wenn Du das 1mal 
feststellst. Vermutlich weißt Du selber längst nicht mehr worum es darin 
gehen sollte...

@Ernst: Wolltest Du nicht noch begründen welchem Zweck nun genau Deine 
CLI/SEI Stümpereien, sorry Basteleien genau dienen?
#7259109
Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>> Εrnst B. schrieb:
>>
>>> Gibt Bonuspunkte für Selbstreflektion.
>>
>> Ich denke, dass er dazu nicht fähig ist.
>>
>> Er hat keinen Code, den er zeigen kann. Er weiß auch gerade nicht, wo er
>> sowas kopieren soll. Alles nur Gelaber.
>
> Mach was Sinnvolleres Wilhelm M. anstatt Dir hier ständig was aus den
> Fingern zu saugen. Code gibts keinen, es langt wenn Du das 1mal
> feststellst.

Alles klar: es gibt keinen, weil Du keinen hast.
Gast #7259151
Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>
>> Alles klar
>
> Hoffentlich.

Die Idee, für Zeitabfragen aus einem 32-Bit-Zähler immer nur ein Byte 
atomar auszulesen und so Interuptsperren und ATOMAR-Konstrukte zu 
vermeiden, ist ja recht interessant. Wenn Wertebereiche und Auflösung 
ausreichen.

Dem TO vom ATOMAR-Konstrukt, von Specherbarrieren, und allgemein von 
allem ausser Assembler abzuraten halte ich für eine Einzelmeinung (sagt 
man doch so, auch wenn es mindestens schon zwei Foristen gibt die sie 
vertreten).

Eine Softwarekonstruktion die fast alles in Interrupts abhandelt und bei 
der das Hauptprogramm "gepflegt schläft" scheint mir nur in wenigen 
Fällen geeignet. Ich würde es eher nicht so machen. Aber auf alle 
Anforderungen der Hardware rechtzeitig zu reagieren erfordert eh eine 
Analyse maximaler Reaktionszeiten und davon abgeleitet maximaler 
Sperrzeiten, und des Abklopfens aller benutzter Bibliotheken darauf, 
dagegen ist dann die Aufteilung zwischen regulärem Kontext und 
Interrupt-Kontext eher ein Streit um des Kaisers Bart.

YMMV.

LG, Sebastian
#7259197
Lesenswert?

Hallo,

habe mir das natürlich angeschaut. Ich habe nur die namespace Verwirrung 
entfernt. :-)
Vorweg, ich habe keine Ahnug was der Syntax wie barrier([&] ... macht. 
Oder access([]{ ... . Ein Array? wo es kein Array gibt noch dazu mit & 
Symbol. Absolut Null Schimmer was das ist. Ich kann mir jedoch davon 
abgesehen den Code erklären was da abläuft.

'flag' wird mit MemoryBarrier in der ISR und main() Zwangsweise frisch 
gelesen bzw. geschrieben. Das wird mittels Barrier Klasse 
Konstruktoraufruf und Zerstörung automatisch 2x aufgerufen. Das läuft 
über mehrer "Funktionsaufrufe". Soweit ist mir der Ablauf klar. im 
Detail gibts aber mehr Fragen wie Antworten.


In der barrier Funktion wird eine Instanz b erstellt aber nie vewendet. 
???
Dann wird eine Funktion f() aufgerufen die es gar nicht gibt. Ähmm 
'grübel'
1
void barrier(const auto f) {
2
  Barrier b;
3
  f();
4
}


Auch in der Access Funktion wird eine 'di' Instanz erzeugt aber nie 
verwendet? Und der unbekannte Syntax ([&]{ und wieder die nicht 
existierende Funktion f(). 'grübel'
1
void access(const auto f)
2
{
3
  DisableInterruptsRestore di;
4
  barrier([&] {
5
    f();
6
  });
7
}


Jetzt muss ich nochmal auf den Vergeich mit volatile zurückkommen. Mit 
der MemoryBarrier wird ja der frische Lese/Schreibzugriff erzwungen. 
Also das was auch mit volatile erzwungen wird. Nur das ohne volatile die 
Variable woanders an anderen Stellen vom Compiler optimiert werden 
könnte. Könnte! Soweit sollte das nun von mir stimmen. Nun kommt meine 
Praxisseite raus wegen dem Könnte! Wenn man eine Variable hat die 
außerhalb von normalen Programmfluss geändert wird und man deswegen 
frischen Lese/Schreibzugriff benötigt, dann ist es ja meistens so das 
man sowieso immer den frischen Wert haben möchte und der Compiler 
sowieso nicht optimieren kann/darf. Zudem werden solche 'volatile' 
Variablen ja nicht verstreut im gesamten Programm verwendet sondern 
üblich nur an ganz bestimmten Stellen, was ja beim Zeitzähler der Fall 
ist. Man fragt den ja nicht an verschiedenen Stellen ab sondern alles 
was nach Zeitablauf erfolgen soll passiert nach dessen gültigen 
Ereigniseintritt. Das heißt die vom Compiler mögliche non volatile 
Optimierung irgendwo anders kommt sowieso nicht zum Zuge. Also warum 
soll man sich in der Praxis das verkomplizierende Konstrukt mit 
MemoryBarrier überhaupt antun? Denn der gezeigte Code macht ja nichts 
anderes was man auch mit volatile machen könnte mit viel weniger 
Programmzeilen. Hier und da kann der Compiler an 'flag' nichts 
optimieren. Jeder Zugriff wird überall frisch benötigt und erzwungen. 
Genau wie mit volatile.

Ich habe verstanden was MemoryBarrier ist und macht. Vielen Dank. Aber 
der Nutzen ist mir nicht klar. Wann mit Optimierungsnutzen für den 
Compiler ist das statt volatile wirklich sinnvoll? Also selbst wenn ich 
100 Rechenkerne habe die alle mit der MemoryBarrier Variable arbeiten 
benötigen alle Rechenkerne den aktuellen Wert. Wo soll dabei eine 
Optimierung für den Compiler möglich sein? Mein Gedanke sollte 
verständlich sein worauf ich hinaus möchte. Ich würde es ja zukünftig 
verwenden wenn mir der Vorteil klar wäre. Wir reden nicht von der 
möglichen Optimierungsmöglichkeit. Wir reden davon in welchen Fällen der 
Compiler überhaupt die Chance zum optimieren wahrnehmen kann. Wenn er 
Compiler seine Trumpfkarte nie ausspielen kann, wie ich denke, dann ist 
der ganze Aufwand für die Katz.

Ich hätte aus Nutzersicht noch ein Problem mit _MemoryBarrier(). Es ist 
kein Anfang und Ende erkennbar. Code der dazwischen steht wird 
"erzwungen". Soweit so gut. Nur man bräuchte ein Anfang und Ende ähnlich 
wie cli/sei vom Namen her oder meinetwegen wie AtomicBlock mit Klammer { 
... } woraus jederzeit ersichtlich wird für den Codeleser was jetzt 
'gekapselt' ist. Denn folgen mehrere im Wechsel ist spätestens nach dem 
2. Aufruf unklar welche Codezeilen dazwischen liegen. Das wird wohl auch 
der Grund sein für die Klassen mit expliziten Dekonstruktor. Weil sonst 
blickt niemand mehr durch.

Darum ging es:
1
#include <avr/cpufunc.h>
2
#include <util/atomic.h>
3
#include <stdint.h>
4

5

6
struct Barrier final {
7
  inline Barrier() {
8
    _MemoryBarrier();
9
  }
10
  inline ~Barrier() {
11
    _MemoryBarrier();
12
  }
13
};
14

15
void barrier(const auto f) {
16
  Barrier b;
17
  f();
18
}
19

20
struct DisableInterruptsRestore final {
21
  inline DisableInterruptsRestore() {
22
    cli();
23
  }
24
  inline ~DisableInterruptsRestore() {
25
    SREG = save;
26
  }
27
  private:
28
    uint8_t save{SREG};
29
};
30

31
void access(const auto f) {
32
  DisableInterruptsRestore di;
33
  barrier([&] {
34
    f();
35
  });
36
}
37

38
volatile uint8_t mcuRegister;
39
uint8_t g;
40
bool flag;
41

42

43
ISR(TCA1_CMP0_vect) {
44
  barrier([] {
45
    ++g;
46
    if (g > 100) flag = true;
47
  });
48
}
49

50
int main(void) {
51
  while (true) {
52
    access([]{
53
      if (flag) {
54
        flag = false;
55
        mcuRegister = 0x01;
56
      }
57
    });
58
  }
59
}
#7259223
Lesenswert?

Veit D. schrieb:
> Jetzt muss ich nochmal auf den Vergeich mit volatile zurückkommen.

Ich stimme dir voll zu. Es sollte schon lesbar bleiben. Das Beispiel mit 
der memory barrier ist deutlich unübersichtlicher als eine Lösung mit 
volatile. Und wenn einem die paar Takte wegen der schlechteren 
Optimierung fehlen, dann man eher ein anderes Problem und es fliegt 
einem das Zeugs an einer anderen Stelle auch um die Ohren.

Das Problem der fehlenden Optimierung mit volatile ist mir im 
Berufsleben noch nie begegnet. Es ist eher theoretischer Natur. Man kann 
es nicht ausschließen aber wie schon geschrieben, dann hat man woanders 
auch Probleme. Dann ist eher das Systemdesign fragwürdig (Auswahl der 
geeigneten MCU) wenn es so eng wird dass die paar nicht optimierten 
Stellen ins Gewicht fallen.

Ja klar, in Assembler wird das alles besser und vor allem trotzdem 
übersichtlich und wartbarer. ;) Man hätte diese Probleme nicht.
Und nein, ich nehme trotzdem kein Assembler, habe ich auch mal ca. 10 
Jahre machen dürfen. :) Hat auch was ja. Aber heute? Nur wenn es ohne 
nicht geht ein paar Zeilen.
Gast #7259236
Lesenswert?

Veit D. schrieb:
> Vorweg, ich habe keine Ahnug was der Syntax wie barrier([&] ... macht.
> Oder access([]{ ... . Ein Array? wo es kein Array gibt noch dazu mit &
> Symbol. Absolut Null Schimmer was das ist.
Eine Lambda Funktion, der alle Instanzeigenschaften als Referenz zur 
Verfügung stehen.
Gast #7259282
Lesenswert?

Sebastian schrieb:
> Die Idee, für Zeitabfragen aus einem 32-Bit-Zähler immer nur ein Byte
> atomar auszulesen und so Interuptsperren und ATOMAR-Konstrukte zu
> vermeiden, ist ja recht interessant. Wenn Wertebereiche und Auflösung
> ausreichen.

Main>Interrupt atomar Lesen/Schreiben wird mit C Pflicht, sonst gehts 
wie schon beschrieben auch "quasi-atomar" in richtiger 
Zugriffs-Reihenfolge mit mehreren Bytes des Zählers. Mit nur 1 Byte 
kommt man aber auch schon weit da für immer längere Zeiträume meist auch 
immer größere Ungenauigkeiten tolerabel sind.
Ich wüsste nicht, welche gebräuchlichen Zeitperioden mal mindestens ab 
1ms bis beliebig lange mit der Methode nicht abgedeckt werden könnten.

> von allem ausser Assembler abzuraten

Kann keine Rede von sein. Fakt bleibt: Asm ist am flexibelsten aber eben 
meist nur für kleinere Programme sinnvoll. Für nicht unbedingt wenige.

> Eine Softwarekonstruktion die fast alles in Interrupts abhandelt und bei
> der das Hauptprogramm "gepflegt schläft" scheint mir nur in wenigen
> Fällen geeignet.

In allen Fällen bei denen der Programm-Funktionsumfang und die 
Interrupt-Belastung überschaubar bleiben. Für nicht unbedingt wenige.

> Analyse maximaler Reaktionszeiten und davon abgeleitet maximaler
> Sperrzeiten, und des Abklopfens aller benutzter Bibliotheken darauf

Auf Sperrzeiten ganz zu verzichten schafft gerade bei hoher 
Interruptfrequenz maximalen Spielraum und erleichtert Entwicklung und 
Debugging ungemein.
#7259325
Lesenswert?

Hallo,

@ 900ss:
Das ich bei Programmierdiskussionen mal Zustimmung bekomme ist auch neu. 
:-)  Mal abwarten ob Wilhelm noch eine Bsp. hat wo der Compiler diese 
Variable optimieren kann.

@ EAF:
Danke. Mit dem Begriff Lambda kann ich arbeiten bzw. nachlesen. Habe 
Lambda bis heute noch nicht benötigt.
#7259482
Lesenswert?

Veit D. schrieb:
> Vorweg, ich habe keine Ahnug was der Syntax wie barrier([&] ... macht.
> Oder access([]{ ... . Ein Array? wo es kein Array gibt noch dazu mit &
> Symbol. Absolut Null Schimmer was das ist. Ich kann mir jedoch davon
> abgesehen den Code erklären was da abläuft.

Den Funktionen wird ein Funktionsobjekt übergeben, in dem Fall ein 
Closure erzeugt durch einen Lambda-Ausdruck -> Funktionales 
Programmieren in C++. Wer Lambda-Ausdrücke verstanden hat, hat C++ 
verstanden ;-)

> In der barrier Funktion wird eine Instanz b erstellt aber nie vewendet.
> ???

Das Idiom nennt sich RAII. Ist eines der einfachten C++-Idiome und 
sollte jedem bekannt sein.

> Dann wird eine Funktion f() aufgerufen die es gar nicht gibt. Ähmm
> 'grübel'

Ist das Funktionsobjekt in der Parametervariablen f: kann eine Funktion, 
ein Funktor oder Closure sein.

>
> Auch in der Access Funktion wird eine 'di' Instanz erzeugt aber nie
> verwendet? Und der unbekannte Syntax ([&]{ und wieder die nicht
> existierende Funktion f(). 'grübel'

RAII

> Jetzt muss ich nochmal auf den Vergeich mit volatile zurückkommen. Mit
> der MemoryBarrier wird ja der frische Lese/Schreibzugriff erzwungen.
> Also das was auch mit volatile erzwungen wird. Nur das ohne volatile die
> Variable woanders an anderen Stellen vom Compiler optimiert werden
> könnte.

Ja. Eine Variable als volatile zu deklarieren ist eigentlich sinnlos, es 
sei denn es ist ein HW-Register, wo jeder Zugriff einen Seiteneffekt 
auslösen soll.

Ansonsten sollte die Zugriffsart ggf. "volatile" sein, und nicht die 
Variable. Und das erreicht man mit einer memory-barrier. Wobei natürlich 
eine wie hier verwendete globale memory-barrier alle(!) ge-cache-ten 
Register zurückschreibt, also auch noch zu viel ist.

Wenn man das noch besser machen will, kann man z.B. explizit einen 
"volatile"-acces machen.

> Jeder Zugriff wird überall frisch benötigt und erzwungen.
> Genau wie mit volatile.

Mach mal einen Test: nimmt eine x-beliebiges, etwas größeres Artefakt, 
einmal mit als volatile qualifizierte Datenstrukturen und andererseits 
einen Zugriff mit memory-barrier.

> Ich habe verstanden was MemoryBarrier ist und macht. Vielen Dank. Aber
> der Nutzen ist mir nicht klar.

Dann hast Du es nicht verstanden.

> Wann mit Optimierungsnutzen für den
> Compiler ist das statt volatile wirklich sinnvoll? Also selbst wenn ich
> 100 Rechenkerne habe die alle mit der MemoryBarrier Variable arbeiten
> benötigen alle Rechenkerne den aktuellen Wert.

Du musst bedenken, dass es bei komplexeren CPUs als die simplen AVR 
neben den Compiler-memory-barriern (Compile-zeit) auch noch die 
CPU-memory-barrier (Laufzeit) gibt.

> Wo soll dabei eine
> Optimierung für den Compiler möglich sein? Mein Gedanke sollte
> verständlich sein worauf ich hinaus möchte. Ich würde es ja zukünftig
> verwenden wenn mir der Vorteil klar wäre. Wir reden nicht von der
> möglichen Optimierungsmöglichkeit. Wir reden davon in welchen Fällen der
> Compiler überhaupt die Chance zum optimieren wahrnehmen kann.

Mach einfach mal in einer ISR:
1
volatile uint8_t g;
2
ISR(...) {
3
    ++g;
4
    if (g > 10) {
5
         ...
6
    }

Dann erkennst Du es: g kann nicht in einem register ge-cahe-ed werden 
wegen volatile.
[/c]

> Ich hätte aus Nutzersicht noch ein Problem mit _MemoryBarrier(). Es ist
> kein Anfang und Ende erkennbar. Code der dazwischen steht wird
> "erzwungen".

Nein. Es werden alle ge-cached-ten Inhalte Zrückgeschrieben und die 
Register-Inhalte invalidiert, müssen also nachgeladen werden.

> Das wird wohl auch
> der Grund sein für die Klassen mit expliziten Dekonstruktor. Weil sonst
> blickt niemand mehr durch.

Wie gesagt: jeder(!) der C++ einsetzt sollte RAII kennen.
Was ich dort geschrieben habe, ist nicht mehr als ein Schulbeispiel, wo 
man explizit den Einsatz eines Kritischen Bereiches und den Einsatz 
einer memory-barrier explizit sehen kann. Ich fand das besser, als den 
ATOMIC_BLOCK, wo genau dasselbe im C-Stil stattfindet, eber m.E. weniger 
sichtbar ist. Also didaktische Gründe.
Gast #7259712
Lesenswert?

Wilhelm M. schrieb:
> Du musst bedenken, dass es bei komplexeren CPUs als die simplen AVR

Wir sind hier aber beim dankenswerterweise simplen AVR.
Hast Du Dir diesen Thread als Vehikel ausgesucht graue C++ Theorie zu 
diskutieren?

> Dann hast Du es nicht verstanden!


Das mag ja alles seine Anwendung und Bedeutung in größeren IT-Kisten 
haben- für das Thread-Thema aber sicher nicht. Möge jeder meiner simplen 
AVRs von der Belastung durch C++ verschont bleiben- und schlicht nur 
seine Aufgabe erledigen.
#7259785
Lesenswert?

Ralf schrieb:
> Auf Sperrzeiten ganz zu verzichten schafft gerade bei hoher
> Interruptfrequenz maximalen Spielraum und erleichtert Entwicklung und
> Debugging ungemein.

Nun, beim AVR gibt es keine Interruptlevel. Du mußt daher jederzeit 
damit rechnen, daß der längste Interrupthandler gerade in Ausführung ist 
und für seine eigene Laufzeit sämtliche anderen Interrupts sperrt. Mit 
Einsprung, Aussprung, Prolog, Epilog, Register retten usw. kommt man 
kaum unter 50 CPU-Zyklen Interruptsperre. Dagegen ist ein atomarer 
Zugriff auf 2 oder 4 Byte einfach nur lächerlich.

Es ist daher auch extrem kontraproduktiv, statt einer globalen Sperre 
nur den speziellen Interrupt zu sperren, mit dem der atomare 
Datenaustausch erfolgen soll. Denn dann hat man wieder das Problem mit 
dem längsten Interrupthandler, der dazwischen grätschen kann. Bzw. bei 
CPUs mit Interruptlevel hat man dann sogar eine mögliche 
Prioritätsinversion.
Gast #7260316
Lesenswert?

Peter D. schrieb:
> Nun, beim AVR gibt es keine Interruptlevel. Du mußt daher jederzeit
> damit rechnen, daß der längste Interrupthandler gerade in Ausführung ist
> und für seine eigene Laufzeit sämtliche anderen Interrupts sperrt. Mit
> Einsprung, Aussprung, Prolog, Epilog, Register retten usw. kommt man
> kaum unter 50 CPU-Zyklen Interruptsperre. Dagegen ist ein atomarer
> Zugriff auf 2 oder 4 Byte einfach nur lächerlich.

Nun, der hier diskutierte AVR hat erstens zwei 
Anwendungs-Interruptlevel.
Mit 50 CPU- Zyklen für einen Interrupt hast Du wahrscheinlich C mit 
seiner umfangreicheren Register-Sicherung im Hinterkopf. So muß das aber 
ganz und gar nicht sein wenn man flexibler ist. Kurzfristige Sperren für 
atomare Zugriffe können je nach Belastung in der Tat lächerlich sein. 
Sie bleiben dennoch überflüssig, erfordern extra Bürokratie in Form von 
AtomicBlocks, die eine extra Ecke sind um die man denken muß und über 
die man wie der TO stolpern kann. Dieser Kritikpunkt ist fast noch 
wichtiger...
#7260326
Lesenswert?

Ralf schrieb:
> erfordern extra Bürokratie in Form von
> AtomicBlocks, die eine extra Ecke sind um die man denken muß

Ach, und bei deiner Lösung ist das besser? Wenn man bei jedem Zugriff 
erstmal überlegen muss, wie man da eine Plausibilitätsprüfung einbaut, 
und was diese alles prüfen und beachten muss?

Das Argument mit "Das ist in einen Getter gekapselt" zählt nicht, da 
kann ich nämlich auch den Atomic-Block drin kapseln.
Gast #7260367
Lesenswert?

Εrnst B. schrieb:
> Ach, und bei deiner Lösung ist das besser? Wenn man bei jedem Zugriff
> erstmal überlegen muss, wie man da eine Plausibilitätsprüfung einbaut,
> und was diese alles prüfen und beachten muss?

Thema war das Problem des TO.
Es ist so simpel wie hier tausendmal beschrieben zu lösen.

Du beziehst Dich jetzt auf das Timing-Management in meinen Programmen 
das ich kurz erläutert hatte. Irgendeine Plausibilitäts-Prüfung wäre 
dort nur dann erforderlich wenn mehrere Prozesse auf denselben Zähler 
schreiben würden. Kann man machen, in aller Regel sind die Zähler aber 
wie beschrieben nur einer bestimmten Aufgabe zugeordnet. Via Asm kann 
dann jede Zählerbyte-Teilmenge problemlos beschrieben und gelesen 
werden. Hier ist die Regel dann meist nur ein Null-Test eines bestimmten 
Zählerbytes vom Hauptprogramm aus. Alternativ ließe sich, für maximal 
Speed, auch ein im Timer-Interrupt gestelltes GPR_GPRx IO-Registerbit 
als Kommunikationsmedium dafür einspannen.
#7260375
Lesenswert?

Ralf schrieb:
> Thema war das Problem des TO.

Und genau für das Problem ist die millionenfach bewährte Standard-Lösung 
eben eine kurze Interrupt-Sperre.
Egal ob man das in Assembler schreibt (CLI/SEI) oder in C mit 
cli()/sei() oder mit dem ATOMIC_BLOCK syntactic-sugar, oder in C++ mit 
einer auto-Variable, die das im Konstruktor+Destruktor verpackt.
Und wenn man wiederverwertbaren Code will und einem ein paar Bytes mehr 
im Flash nicht stören, nimmt man statt SEI eben ein Save&Restore vom 
SREG.

Und nein, das Argument mit der gesteigerten Interrupt-Latenz zählt auch 
nicht. Deine Lösung verlängert die Timer-ISR mehr als es eine kurze 
Sperre beim Auslesen tun würde, insofern ist deine Lösung da auch 
schlechter.
Beitrag #7260385 wurde von einem Moderator gelöscht.
Gast #7260418
Lesenswert?

Εrnst B. schrieb:
> Und genau für das Problem ist die millionenfach bewährte Standard-Lösung
> eben eine kurze Interrupt-Sperre.

Klar. Man hat das immer schon so gemacht. Dann machs doch weiter so.

Εrnst B. schrieb:
> Deine Lösung verlängert die Timer-ISR mehr als es eine kurze
> Sperre beim Auslesen tun würde

Die Lösung für den TO kommt mit dem Sekundenzählen im Interrupt in Summe 
kürzer und einfacher.

Redest Du von meinem Zähler-Zeitmanagement hast Du vermutlich Recht.
Nur ist dessen Zielrichtung gar nicht maximale Performance sondern 
bequem-übersichtliches, problemfreies Zeitmanagement für's Hauptprogramm 
und dessen einzelne Bestandteile. Für ein Hauptprogramm, welches für 
seine Zwecke niemals in die globale Interruptsperrung/freigabe 
eingreift. Das hat in gewissem Sinne was von Kapselung und Trennung 
selbstständiger Programmebenen. Auf diese Weise lassen sich gewisse 
Interrupt-Vorlagen mit einem bestimmten Portfolio an Diensten 
(Zeit-Management fürs Hauptprogramm ist nur eine Aufgabe) für viele 
Projekte wiederverwenden.

Nop schrieb:
> Daß man mit C++ einfachste Probleme solange verkomplizieren kann, bis
> man sie ausführlich erklären muß, hat keiner bezweifelt. Ist ansonsten
> aber überflüssig, kann also weg.

Das hätte man nicht besser ausdrücken können :)
#7260466
Lesenswert?

Ralf schrieb:
> Wozu dann noch AtomicBlocks im Hauptprogramm?

na zum Auslesen des sekunden-Zählers, gekapselt in einem Getter, zum 
x-ten mal...

Mag manchmal nicht nötig sein, aber so funktioniert der Code immer & 
garantiert, auch wenn ich ihn in einem anderen Projekt mit anderen 
Rahmenbedingungen recycle.

Darum geht es mir: Sauberen Code zu schreiben, der reproduzierbar 
funktioniert.

Nicht irgendwas planlos zusammenschustern, und dann ewig dran rumdoktorn 
bis es vielleicht meistens gut funktioniert, solange bis sich irgendwas 
ändert.
Gast #7260473
Lesenswert?

Εrnst B. schrieb:
> na zum Auslesen des sekunden-Zählers

Wozu denn? Um den Puls zur Messung vom Hauptprogramm auszugeben?
Das erledigt man im Interrupt selbstredend mit.

> Darum geht es mir: Sauberen Code zu schreiben, der reproduzierbar
> funktioniert.

Das schaffe ich genauso. Ohne sinnlose Interrupt-Sperren.

> Nicht irgendwas planlos zusammenschustern, und dann ewig dran rumdoktorn
> bis es vielleicht meistens gut funktioniert, solange bis sich irgendwas
> ändert.

Meinen Plan hab ich beschrieben. Und beantworte Nachfragen dazu gerne.
Gast #7260480
Lesenswert?

Ralf schrieb:
> Wozu denn? Um den Puls zur Messung vom Hauptprogramm auszugeben?
> Das erledigt man im Interrupt selbstredend mit.

> Das schaffe ich genauso. Ohne sinnlose Interrupt-Sperren.

> Meinen Plan hab ich beschrieben. Und beantworte Nachfragen dazu gerne.

->
1
goto Threadanfang;


Hiiiilllffeeeeeee! Wir sind gefangen!
#7260518
Lesenswert?

Weil Ralph ja keinen Code liefert, schreibe ich seinen ASM-Code hier mal 
als C++. Und der Compiler macht daraus dasselbe, wie er per Hand machen 
würde, wenn der Ralph das denn könnte.
1
template<uint8_t N>
2
struct Timer {
3
    static void isr() {
4
        ++c;
5
    }
6
    template<uint8_t B>
7
    static void whenByteIsZero(auto f) {
8
        Memory::barrier([&]{
9
            if (etl::nth_byte<B>(c) == 0_B) {
10
                f();
11
            }
12
        });
13
    }
14
private:
15
    inline static uint32_t c;
16
};
17

18
using timer0 = Timer<0>;
19

20
ISR(TCA0_CMP0_vect) {
21
    timer0::isr();
22
}
23

24
int main() {
25
    while (true) {
26
        timer0::whenByteIsZero<1>([]{
27
            VPORTA_OUT = 0x01;
28
        });
29
    }
30
}
#7260532
Lesenswert?

Und damit Ralph noch etwas lernen kann, hier der ASM-Code aus dem 
vorigen Post:
1
__RAMPZ__ = 0x3b
2
__CCP__ = 0x34
3
.text
4
.type   __vector_9, @function
5
__vector_9:
6
__gcc_isr 1      ;
7
push r25                 ;
8
push r26                 ;
9
push r27                 ;
10
lds r24,Timer<(unsigned char)0>::c       ;  c, c
11
lds r25,Timer<(unsigned char)0>::c+1     ;  c, c
12
lds r26,Timer<(unsigned char)0>::c+2     ;  c, c
13
lds r27,Timer<(unsigned char)0>::c+3     ;  c, c
14
adiw r24,1       ;  tmp45,
15
adc r26,__zero_reg__     ;
16
adc r27,__zero_reg__     ;
17
sts Timer<(unsigned char)0>::c,r24       ;  c, tmp45
18
sts Timer<(unsigned char)0>::c+1,r25     ;  c, tmp45
19
sts Timer<(unsigned char)0>::c+2,r26     ;  c, tmp45
20
sts Timer<(unsigned char)0>::c+3,r27     ;  c, tmp45
21
pop r27          ;
22
pop r26          ;
23
pop r25          ;
24
__gcc_isr 2      ;
25
reti
26
__gcc_isr 0,r24
27
.size   __vector_9, .-__vector_9
28
.section        .text.startup,"ax",@progbits
29
.type   main, @function
30
main:
31
ldi r24,lo8(1)   ;  tmp52,
32
.L4:
33
lds r25,Timer<(unsigned char)0>::c+1     ;  tmp49, c
34
cpse r25,__zero_reg__    ;  tmp49,
35
rjmp .L3         ;
36
out 0x1,r24      ;  MEM[(volatile uint8_t *)1B], tmp52
37
.L3:
38
rjmp .L4                 ;
#7260570
Lesenswert?

Ralf schrieb:
> Das schaffe ich genauso.
Dann zeig es.

> Meinen Plan hab ich beschrieben.
"Rummurksen, bis es nicht mehr ganz so oft abstürzt?"

Oder war dein Plan:
"den TE mit einer Spezial-Sonderlösung verwirren, die zwar in diesem 
Einzelfall erstmal funktioniert, ihm aber im nächsten Projekt dermaßen 
auf die Füße fällt, dass er noch Wochen danach Kopfschmerzen hat?

> Und beantworte Nachfragen dazu gerne.

Nachfrage: wie schaut der Quelltext aus?
#7260578
Lesenswert?

Hallo,

ich weiß zwar nicht worauf genau ich testen soll, habe jedoch einmal ein 
asmdump erstellt. Ich kann da jetzt keinen Unterschied in der ISR und 
dem flag Zugriff in der main erkennen. Alles der gleiche Code. Was mich 
ehrlich gesagt nicht wundert, denn der Compiler kann ja hier nichts 
optimieren. Wo soll er optimieren? An welcher Stelle? Es wird wie schon 
gesagt an allen Stellen ein frischer Zugriff benötigt.

>> Ich hätte aus Nutzersicht noch ein Problem mit _MemoryBarrier(). Es ist
>> kein Anfang und Ende erkennbar. Code der dazwischen steht wird
>> "erzwungen".

> Nein. Es werden alle ge-cached-ten Inhalte Zrückgeschrieben und die
> Register-Inhalte invalidiert, müssen also nachgeladen werden.

Hier hast du meine Frage falsch verstanden. Alles was mit MemoryBarrier 
erfolgen soll muss doch zwischen zwei Aufrufen stehen.
 _MemoryBarrier();
...
...
 _MemoryBarrier();

Wenn das jetzt mehrfach erfolgen muss wie etwa

 _MemoryBarrier();
...
 _MemoryBarrier();
...
 _MemoryBarrier();
...
 _MemoryBarrier();
...
 _MemoryBarrier();
...
 _MemoryBarrier();

Wie soll man dann noch erkennen welche Codezeilen mit und welche ohne 
MemoryBarrier erfolgen?
#7260592
Lesenswert?

MaWin schrieb:
> Veit D. schrieb:
>> Alles was mit MemoryBarrier
>> erfolgen soll muss doch zwischen zwei Aufrufen stehen
>
> Nein. Meistens nicht.
> Meistens haben die zwei Threads-of-execution jeweils eine Barrier.

Irgendwie raff ich das nicht oder mein Gedankenproblem wird nicht 
verstanden. Wenn im Code nur einmal der Aufruf MemoryBarrier() steht, 
woher  weiß der Compiler welche Variablen er frisch einlesen/schreiben 
soll? Alle davor? Alle danach? Wo zieht der Aufruf seine Grenze? Im 
AtomicBlock gibts eine Klammer damit ist der Fall klar. Zwischen den 
Klammern ist AtomicBlock gültig. Mit cli und sei ist der Fall auch klar. 
Dazwischen erfolgt keine Interruptunterbrechung. Was ist mit Einen 
MemoryBarrier() Aufruf?
Wilhelm ruft in seiner Klasse automatisch 2x MemoryBarrier() auf. 2x.
Gast #7260604
Lesenswert?

Veit D. schrieb:
> Wenn im Code nur einmal der Aufruf MemoryBarrier() steht,
> woher  weiß der Compiler welche Variablen er frisch einlesen/schreiben
> soll? Alle davor? Alle danach?

Selbstverständlich die davor. Das ist doch triviale Logik.
Die danach kann er nicht frisch einlesen, weil die noch gar nicht 
eingelesen wurden.
Die werden dann eben nach der Barriere eingelesen.

> Im AtomicBlock gibts eine Klammer damit ist der Fall klar.

Mit Klammern ist überhaupt nichts klar. Die haben überhaupt keine 
Barrierenfunktion.

> Wilhelm ruft in seiner Klasse automatisch 2x MemoryBarrier() auf. 2x.

Wilhelms Code ist auch ziemlicher Käse.
Der verkompliziert das ohnehin schon nicht ganz triviale Problem der 
memory barriers ohne Grund weiter.
Gast #7260641
Lesenswert?

@Veit D. (devil-elec)

Ich würde auch einmal diese Lektüre empfehlen:

https://en.cppreference.com/w/c/atomic/memory_order

Dort werden generelle Prinzipien und Ordering-Strategien besprochen.
Barriers sind nur Mittel zum Zweck, um diese Strategien umzusetzen.
Man sollte die Prinzipien und Strategien also vorher verstehen, bevor 
man sie mit Barriers anwendet.
Deine Frage, wie viele Barriers man braucht, deutet eindeutig darauf 
hin, dass du diese Grundlagen nicht verstanden hast.

Wenn man ein Bild aufhängen will, dann beschäftigt man sich auch nicht 
als erstes mit dem Durchmesser des Bohrers.
#7260676
Lesenswert?

Hallo,

ist denn hier wirklich niemand im Stande eine einfache Frage zu 
beantworten?

Ich frage nach wo die Abgrenzung ist und bekomme alles davor als 
Antwort. Ganz prima. Kann doch nicht sein.
Ich mach das Bsp. mit AtomicBlock und bekomme die Antwort hat keine 
Barrierfunktion.
Menno. Will man nicht oder kann man nicht?
Natürlich hat AtomicBlock nichts mit Barrier zu tun. Es geht um die 
Klammern. Um die klare Abgrenzung worauf sich AtomicBlock bezieht.
Mit MemoryBarrier sehe ich keinen klaren abgegrenzten Anweisungsblock. 
Wenn man mir sagt alles davor ist das keine Antwort auf meine Frage. Auf 
wieviel Variablenzugriffe davor gilt denn dann ein MemoryBarrier Aufruf? 
Wenn der für alle davor gilt wäre das ja vollkommen sinnfrei. Man will 
es ja nur auf bestimmte Variablen anwenden.
Gast #7260683
Lesenswert?

Veit D. schrieb:
> ist denn hier wirklich niemand im Stande eine einfache Frage zu
> beantworten?

Gerne, danke.

> Ich frage nach wo die Abgrenzung ist

Die Abgrenzung ist an der Barriere. Was verstehst du daran denn nicht?

> und bekomme alles davor als Antwort.

Hilfe hilfe, die helfen mir und geben mir Informationen!!

> Es geht um die Klammern

Nein. Klammern haben nichts mit dem Konzept von Barriers zu tun. Vergiss 
das komplizierte C++-Beispiel.
Das verwirrt nur.

> Auf
> wieviel Variablenzugriffe davor gilt denn dann ein MemoryBarrier Aufruf?

Auf alle.

> Wenn der für alle davor gilt wäre das ja vollkommen sinnfrei.

Nein. Warum?

> Man will
> es ja nur auf bestimmte Variablen anwenden.

Ja. Aber "bestimmte" ist eine Untermenge von "alle".

Und ja, es gibt auch Barrieren, die nur auf bestimmte Variablen wirken.
Siehe: https://en.cppreference.com/w/c/atomic/memory_order
Es ist aber nicht so, dass diese Variablen dann an ihren Namen irgendwie 
benannt werden. Sondern die Barrier hat bestimmte Eigenschaften (z.B. 
Load-Acquire-Semantik) und wirkt deshalb nur auf bestimmte 
Zugriffsarten, aber nicht auf alle.

Lies dich doch bitte ein. Das ist kein triviales Thema, was man eben mal 
in einem Forum lernt.
Gast #7260694
Lesenswert?

Veit D. schrieb:

> Wenn der für alle davor gilt wäre das ja vollkommen sinnfrei. Man will
> es ja nur auf bestimmte Variablen anwenden.

Der Trick an der Sache ist, daß Du die Barrier beim Schreiben direkt 
danach anwendest und beim Lesen direkt davor. Im sehr einfachen Beispiel 
von Wikipedia [1]:

Thread #1 Core #1:
1
 while (f == 0);
2
 // Memory fence required here
3
 print x;

Thread #2 Core #2:
1
 x = 42;
2
 // Memory fence required here
3
 f = 1;

Also in Thread 2 nach dem Schreiben von x, weil f erst geschrieben 
werden darf, wenn x auf 42 steht. Und in Thread 1 vor dem Lesen von x, 
weil x erst gelesen werden soll, wenn die Kontrollogik mit der 
while-Schleife durch ist.

Es gibt da keinen Barrier-Block, sondern ein Paar, das an zwei ganz 
verschiedenen Stellen steht. Hier in zwei Threads, geht aber mit 
Interrupt vs. Anwendung ähnlich. Dieses Paar wirkt zusammen.

[1] https://en.wikipedia.org/wiki/Memory_barrier
Gast #7260696
Lesenswert?

Veit D. schrieb:
> ist denn hier wirklich niemand im Stande eine einfache Frage zu
> beantworten?

Bist du denn in der Lage eine einfache Frage zu einem komplexen Problem 
zu stellen?
Offensichtlich ist doch wohl, dass der Compiler zwecks Optimierung, 
Variablen in Register hält.
Damit ist die eigentlich fundamentale Notwendigkeit der Datenkonsistenz 
gebrochen. Was nicht schlimm ist, solange nicht einer "heimlich" die 
Variablen im Speicher manipuliert.
z.B. in einer ISR

Die Memory Barriere soll genau die Konsistenz wieder herstellen. Also 
muss sie natürlich VOR dem kritischen Zugriff gesetzt werden.
Und natürlich nochmal, bevor die ISR wieder auf die Variable zugreifen 
muss/kann, wenn das Hauptprogramm auch die Variable manipuliert.
#7260731
Lesenswert?

Hallo,

> Bist du denn in der Lage eine einfache Frage zu einem komplexen Problem
> zu stellen?

Bist du in der Lage eine einfache Frage zu verstehen? Anders gefragt. 
Bist du in der Lage eine einfache Frage zu erkennen?

Ich kann auch so pampig antworten.

Ihr steckt wahrscheinlich so tief im Detail das niemand meine Frage 
versteht. Kann doch nicht sein. 'Nop' kommt dem jetzt sehr nahe. Mal 
sehen was sich daraus machen lässt.
Gast #7260742
Lesenswert?

Veit D. schrieb:
> Ich kann auch so pampig antworten.

Das haben wir bereits gemerkt.

> Ihr steckt wahrscheinlich so tief im Detail das niemand meine Frage
> versteht.

Wenn jemand eine Frage nicht versteht, dann trägt niemals der Gefragte 
die Schuld daran. Solltest du dir allgemein merken.

> Kann doch nicht sein.

Genau.
Gast #7260755
Lesenswert?

Veit D. schrieb:
> Bist du in der Lage eine einfache Frage zu verstehen? Anders gefragt.
> Bist du in der Lage eine einfache Frage zu erkennen?
>
> Ich kann auch so pampig antworten.

Ich bin nicht für deine Denkblockaden verantwortlich, auch wenn du dir 
das noch so gerne wünscht!

Veit D. schrieb:
> Ich mach das Bsp. mit AtomicBlock und bekomme die Antwort hat keine
> Barrierfunktion.
> Menno. Will man nicht oder kann man nicht?
> Natürlich hat AtomicBlock nichts mit Barrier zu tun.

Natürlich implementieren die Macros aus util/atomic.h auch Memory 
Barrieren!
Das lässt sich leicht im QuellCode nachweisen.
Auch die Macros in interrupts.h tun das, zumindest cli() und sei() 
welche in atomic.h verwendet werden.
Gast #7260776
Lesenswert?

Veit D. schrieb:
> Es geht um die Klammern.
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) braucht keine Klammern.

Veit D. schrieb:
> Mit MemoryBarrier sehe ich keinen klaren abgegrenzten Anweisungsblock.
Das ist richtig!
Weil es keinen Anweisungsblock hat.
Die Barriere stellt die Datenkonsistenz wieder her.
Mehr nicht.

Veit D. schrieb:
> Auf
> wieviel Variablenzugriffe davor gilt denn dann ein MemoryBarrier Aufruf?
> Wenn der für alle davor gilt wäre das ja vollkommen sinnfrei. Man will
> es ja nur auf bestimmte Variablen anwenden.

Die Barriere wirkt auf ALLE Variablen, welche gerade in Registern 
gehalten werden und noch nicht im Speicher gesichert wurden.
Was jetzt günstiger ist, wird man wohl im Einzelfall entscheiden dürfen
Gast #7260840
Lesenswert?

MaWin schrieb:
> Du scheinst Spaß daran zu haben triviale Probleme möglichst kompliziert
> zu schreiben.

Bingo. Wir teilen tatsächlich wieder denselben Eindruck.

Εrnst B. schrieb:
> Oder war dein Plan:
> "den TE mit einer Spezial-Sonderlösung verwirren, die zwar in diesem
> Einzelfall erstmal funktioniert, ihm aber im nächsten Projekt dermaßen
> auf die Füße fällt, dass er noch Wochen danach Kopfschmerzen hat?

Bis zur Vorstellung meines Timer-Managements war das Problem des TO ja 
längst gelöst, es sollte verdeutlichen wie einfach, intuitiv und 
übersichtlich Timing-Aufgaben generell angegangen werden können. Ohne 
AtomicBlockMemoryBarriereWissenschaften.

Wilhelm M. schrieb:
> Weil Ralph ja keinen Code liefert, schreibe ich seinen ASM-Code
> hier mal
> als C++. Und der Compiler macht daraus dasselbe, wie er per Hand machen
> würde, wenn der Ralph das denn könnte.
> template<uint8_t N>
> struct Timer {
>     static void isr() {
>         ++c;
>     }
>     template<uint8_t B>
>     static void whenByteIsZero(auto f) {
>         Memory::barrier([&]{
>             if (etl::nth_byte<B>(c) == 0_B) {
>                 f();
>             }
>         });
>     }
> private:
>     inline static uint32_t c;
> };
> using timer0 = Timer<0>;
> ISR(TCA0_CMP0_vect) {
>     timer0::isr();
> }
> int main() {
>     while (true) {
>         timer0::whenByteIsZero<1>([]{
>             VPORTA_OUT = 0x01;
>         });
>     }
> }

Meine Güte, was für ein Irrgarten.
Der Assembler-Code schaut noch schlimmer aus.

Eine Anzahl von bis 255 32-Bit Timern 0-dekrementieren lässt sich in Asm 
z.B. für 4 Stück recht knapp und übersichtlich wie folgt formulieren:
1
;TDC    TIMER-DOWNCOUNTER (*4)
2
;               (x= DoubleWord 0-7: zählt alle HSEK/2.56Sek/10.92Min/46.6Stu)
3
;               (HSEK/xSEK/xMIN/xSTU)
4
;    1Sek= 64/00/00/00, 1Min= 70/17/00/00, 1Stu= 40/7E/05/00
5
;    1Tag= 00/D6/83/00, 1Wo= 00/DA/9A/03
6
 
7
tdc:    ldi  ZL,low(DC0HSEK)
8
    ldi  ZH,high(DC0HSEK)
9
    ldi  YL,4      ;4 DOWNCOUNTER
10
tdc1:    ldd  XL,Z+0
11
    ldd  XH,Z+1
12
    sbiw  XH:XL,1
13
    brsh  tdc2
14
    ldd  XL,Z+2
15
    ldd  XH,Z+3
16
    sbiw  XH:XL,1
17
    brlo  tdc3
18
    std  Z+2,XL
19
    std  Z+3,XH
20
    ser  XL
21
    ser  XH
22
tdc2:    std  Z+0,XL
23
    std  Z+1,XH
24
tdc3:    adiw  ZH:ZL,4
25
    dec  YL
26
    brne  tdc1
27
                ret
28

29
DC0HSEK:        .BYTE 1         ;[4010H] not available
30
DC0SEK:    .BYTE 1    ;[4011H] STARTTIMER
31
DC0MIN:    .BYTE 1    ;[4012H] not available
32
DC0STU:    .BYTE 1    ;[4013H] not available
33
DC1HSEK:        .BYTE 1         ;[4014H] not available
34
DC1SEK:    .BYTE 1    ;[4015H] PRESENCE CONTROL
35
DC1MIN:    .BYTE 1    ;[4016H] not available
36
DC1STU:    .BYTE 1    ;[4017H] not available
37
DC2HSEK:        .BYTE 1         ;[4018H] not available
38
DC2SEK:    .BYTE 1    ;[4019H] VALIDDATA TIMEOUT
39
DC2MIN:    .BYTE 1    ;[401AH] not available
40
DC2STU:    .BYTE 1    ;[401BH] not available
41
DC3HSEK:        .BYTE 1         ;[401CH] not used
42
DC3SEK:    .BYTE 1    ;[401DH] not used
43
DC3MIN:    .BYTE 1    ;[401EH] not used
44
DC3STU:    .BYTE 1    ;[401FH] not used
#7260843
Lesenswert?

Veit D. schrieb:

> Irgendwie raff ich das nicht oder mein Gedankenproblem wird nicht
> verstanden. Wenn im Code nur einmal der Aufruf MemoryBarrier() steht,
> woher  weiß der Compiler welche Variablen er frisch einlesen/schreiben
> soll? Alle davor? Alle danach? Wo zieht der Aufruf seine Grenze? Im
> AtomicBlock gibts eine Klammer damit ist der Fall klar. Zwischen den
> Klammern ist AtomicBlock gültig. Mit cli und sei ist der Fall auch klar.
> Dazwischen erfolgt keine Interruptunterbrechung. Was ist mit Einen
> MemoryBarrier() Aufruf?
> Wilhelm ruft in seiner Klasse automatisch 2x MemoryBarrier() auf. 2x.

Genau, es ist das direkte Äquivalent zu ATOMIC_BLOCK. Schau Dir das 
Macro an. Der CPP ersetzt den init-Ausdruck der for-Schleife durch ein 
cli(), das ist wiederum ein cli in asm und memory-barrier. Und am Ende 
im restore-Ausdruch der out-of-scope gehenden sreg_save Variablen kommt 
auch eine memory-barrier. Damit ist dieser Block universell einsetzbar. 
Zwei unmittelbar aufeinanderfolgende memory-bariier kollabieren 
natürlich zu einer, denn dazwischen git es keine Register, die evtl. 
dirty sein könnten.
Gast #7260850
Lesenswert?

Wilhelm M. schrieb:
> Doch: das Macro beinhaltet zwei memory-barrier, eine am Block-Anfang und
> eine am -Ende. Genau wie ich es in der C++-Alternative geschrieben
> haben.

Für 99% aller Anwendungsfälle als Ablaufsynchronisation ist eine von den 
beiden Barriers überflüssig.
Deine Lösung ist unnötig kompliziert.

Ralf schrieb:
> Ohne AtomicBlockMemoryBarriereWissenschaften.

Das geht nicht.
Auch nicht in asm.
#7260856
Lesenswert?

MaWin schrieb:
> Wilhelm M. schrieb:
>> Doch: das Macro beinhaltet zwei memory-barrier, eine am Block-Anfang und
>> eine am -Ende. Genau wie ich es in der C++-Alternative geschrieben
>> haben.
>
> Für 99% aller Anwendungsfälle als Ablaufsynchronisation ist eine von den
> beiden Barriers überflüssig.
> Deine Lösung ist unnötig kompliziert.

Und nochmal: es ist einfach das direkte Äquivalent zu ATOMIC_BLOCK, 
sonst nichts. Mit dem Vorteil, das alle Operationen nun sichtbar sind. 
Auch Beit D. hat das nun gesehen, das hatte er bei ATOMIC_BLOCK so nicht 
bemerkt.
Gast #7260863
Lesenswert?

Wilhelm M. schrieb:
> Und nochmal: es ist einfach das direkte Äquivalent zu ATOMIC_BLOCK,
> sonst nichts.

Ja. Habe ich verstanden. Es ergibt aber trotzdem keinen Sinn.
Eine Barrier, ohne lock/mutex oder cli/sei, ist halt kein Block.
Das Konzept eines Blocks ergibt dort überhaupt gar keinen Sinn.

> Mit dem Vorteil, das alle Operationen nun sichtbar sind.

Nö. Es verbirgt die Barriere.
Gast #7260925
Lesenswert?

MaWin schrieb:
> Ralf schrieb:
>> Ohne AtomicBlockMemoryBarriereWissenschaften.
>
> Das geht nicht.
> Auch nicht in asm.

Für besagtes Zeitmanagement mal mindestens.
Erzähl doch keinen Unsinn.
Einfach herrlich diese "Trivialarchitektur"!
Warum kompliziert wenn es auch einfach geht!
Mögen uns diese Chips noch lange erhalten bleiben!
#7261094
Lesenswert?

MaWin schrieb:
> Das geht nicht.
> Auch nicht in asm.

Siehe mein letztes Beispiel aus

Beitrag "Re: AVR DB - oder doch ein Compiler-Fehler?"

Das ist genau das was Ralph ohne Code mit Geschwafel beschrieben hat. In 
diesem Spezialfall (nur 8-Bit atomare Lese/Schreibvorgänge, "Timer" mit 
zunehmender Quantisierung) geht es auch in C / C++ ohne cli/sei. 
Natürlich sollte man das mit entsprechende static_asserts absichern, 
dass diese Annahmen zutreffen, damit es später nicht irgendwo knallt.
Natürlich muss man in C / C++ hier eine memory-barrier einbauen. Diese 
kleine Maßnahme ist notwendig, damit man sich trotzdem auf die 
Optimierungen des Compilers verlassen kann, ohne über irgendwelchen ASM 
Murks nachdenken zu müssen.
Gast #7261398
Lesenswert?

Bei manchem Zeitgenossen kann einfach nicht sein was nicht sein darf.
Dabei muss man sich eigentlich nicht wundern, wenn sich fette Bulldozer 
in gerade mal 8 Bit breiten Nischen etwas schwerer tun.

P.S. Wie nennt man ein neues C++ Feature? Verschlimmbesserung!
Gast #7261459
Lesenswert?

Ralf schrieb:
> wenn sich fette Bulldozer
> in gerade mal 8 Bit breiten Nischen etwas schwerer tun.
>
> P.S. Wie nennt man ein neues C++ Feature? Verschlimmbesserung!

Nur weil etwas im Quellcode gesprächig ist, heißt das noch lange nicht, 
dass es im Binary groß ist.
C++ und viele andere Sprachen arbeiten nach dem Konzept der 
zero-cost-abstraction.

Und grundsätzlich halte ich das für eine gute Sache.
Man darf es halt nicht übertreiben und Abstraktionen nicht nur zum 
Selbstzweck einfügen.
Gast #7261509
Lesenswert?

MaWin schrieb:
> dass es im Binary groß ist

Das bekäme man mit hinreichend guten Spezial-Kenntnissen ja noch hin- 
sprich klein und schnell genug. Bulldozer meint eher die mangelnde 
Flexibilität dabei (siehe: atomarer Zählerzugriff) und den großen zu 
beherrschenden Sprachumfang- ohne gleichzeitig und zwingend den "Kontakt 
zur Realität da ganz unten" vermittelt zu bekommen. Abstrakt ist und 
bleibt abstrakt.

MaWin schrieb:
> Und grundsätzlich halte ich das für eine gute Sache.
> Man darf es halt nicht übertreiben und Abstraktionen nicht nur zum
> Selbstzweck einfügen.

Da sind wir sogar einer Meinung. Aber nur dort wo es wirklich Sinn 
macht- und das heißt bei größeren Architekturen und nicht bei 
Simply-AVR. Wobei- wer selbst diese mit Bulldozern bearbeiten will und 
Spaß dran hat warum nicht. Er oder Sie darf sich bloß nicht wundern wenn 
in diesem Fall so manches mit einfacheren Methoden flexibler zu 
bewerkstelligen ist.
Gast #7261511
Lesenswert?

EAF schrieb:
> ASM Priester verstehen unter Abstraktion häufig was anderes. Die halten
> gerne ihre Sprache, für die, mit den meisten/besten
> Abstraktionsmöglichkeiten

Was für ein Unfug.
AVR ist so einfach, da brauchts schlicht keine Abstraktion. Und 
Priestertum schon gar nicht.
#7261519
Lesenswert?

Ralf schrieb:
> Das bekäme man mit hinreichend guten Spezial-Kenntnissen ja noch hin-
> sprich klein und schnell genug. Bulldozer meint eher die mangelnde
> Flexibilität dabei (siehe: atomarer Zählerzugriff) und den großen zu
> beherrschenden Sprachumfang- ohne gleichzeitig und zwingend den "Kontakt
> zur Realität da ganz unten" vermittelt zu bekommen.

Schau Dir meinen Code und das Assembler-Listing nochmal an: es ist genau 
Dein Prinzip (soweit ich das aus Deinem Geschwafel entnehmen konnte) und 
verwendet keine Interrupt-Sperre und ist trotzdem korrekt.

Leider hast Du dann danach etwas später Dein ASM-Code Schnipsel gezeigt, 
was Du wohl in der ISR einsetzen würdest. Aber das ist natürlich noch 
keine vollständige ISR geschweige denn ein komplettes Programm.
Also: zeige alles!

>Abstrakt ist und
> bleibt abstrakt.

Manche Leute können abstrakt denken, andere eben nicht.
Gast #7261522
Lesenswert?

EAF schrieb:
> Ein Compiler formt aus Abstraktionen (Klassen, Templates, usw) ganz
> konkrete Anwendungen.

Wen interessiert was der Compiler "formt"?
Selbstredend den gleichen Maschinencode.
Interessant ist natürlich das Interface,
die Abstraktionen mit denen der Programmierer
arbeitet.

EAF schrieb:
> Und du bist ganz offensichtlich der unbestechliche "Experte", welcher
> die ganze Welt von solch einem Blödsinn überzeugen will.

Komm einfach von der persönlichen Schiene runter und konzentriere Dich 
auf die Fakten welche die Technik vorgibt.
Gast #7261524
Lesenswert?

Wilhelm M. schrieb:
> Manche Leute können abstrakt denken, andere eben nicht.

Abstraktionen ist dann eine gute Sache wenn sie wirklich nötig und 
hilfreich sind. Im übrigen wurden sie ja gerade erschaffen um dem 
Verständnis auf die Sprünge zu helfen. Nur hat das Schatten-Seiten und 
einen Preis. Und man kann es dabei arg übertreiben.
Gast #7261545
Lesenswert?

EAF schrieb:
> Hier sage ich mal: Nein!

Ach, dann schau Dir mal die Vorworte und Einleitungen dicker OOP Wälzer 
oder der tausenden anderen Lernbücher an :)

> Einmal schreiben, tausendfach wiederverwenden, egal auf welcher
> Hardware.

Ja, die liebe Portabilität.
Die man zunächst mal brauchen muß.
Also ich brauche sie nicht weil mir AVRs für alle Zwecke ausreichen.
Mit den richtigen Konzepten kann man innerhalb einer Architektur auch 
vieles wiederverwenden.

Und dann gibts da bei Hochsprache und bei maschinennahen Programmteilen 
so manch kleine aber feine nötige Anpassung. Ganz so einfach ist das 
nämlich nicht. Schließlich kommt das facettenreiche Gesicht eines 
Ungetüms wie C++ in vielerlei Programmierstilen daher. Mal eben was vom 
unbekannten Kollegen wiederweiterverwenden kann auch schwierig werden. 
Dennoch: Portabilität, oder sagen wir besser maximal alle 
Voraussetzungen dafür bleiben ein Plus von C (Plus Plus). Hatte ich das 
irgendwo bestritten?
Gast #7261566
Lesenswert?

Ralf schrieb:
> Also ich brauche sie nicht weil mir AVRs für alle Zwecke ausreichen.
> Mit den richtigen Konzepten kann man innerhalb einer Architektur auch
> vieles wiederverwenden.

Vergleich:
> Ein Frosch, der im Brunnen lebt, beurteilt das Ausmaß des Himmels nach dem 
Brunnenrand.
https://german.cri .cn/1833/2011/05/27/1s157501.htm

PS:
> Der Beitrag scheint Spam zu enthalten: ".cn/"
Ein Leerzeichen eingefühgt
#7262013
Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>> Manche Leute können abstrakt denken, andere eben nicht.
>
> Abstraktionen ist dann eine gute Sache wenn sie wirklich nötig und
> hilfreich sind. Im übrigen wurden sie ja gerade erschaffen um dem
> Verständnis auf die Sprünge zu helfen. Nur hat das Schatten-Seiten und
> einen Preis. Und man kann es dabei arg übertreiben.

Du hast mal wieder "vergessen", Deinen Code für ein vollständiges 
Beispiel zu zeigen, und nicht nur den Teil für ein Inkrement der 4 
Variablen. Nimm einfach mein sehr simples, letztes Beispiel aus 
funktionales Vorlage.
Gast #7262121
Lesenswert?

EAF schrieb:
> Ralf schrieb:
>> Also ich brauche sie nicht weil mir AVRs für alle Zwecke ausreichen.
>> Mit den richtigen Konzepten kann man innerhalb einer Architektur auch
>> vieles wiederverwenden.
>
> Vergleich:
>> Ein Frosch, der im Brunnen lebt, beurteilt das Ausmaß des Himmels nach dem
> Brunnenrand.
> https://german.cri .cn/1833/2011/05/27/1s157501.htm
>
> PS:
>> Der Beitrag scheint Spam zu enthalten: ".cn/"
> Ein Leerzeichen eingefühgt

Bist ja echt ne traurige Gestalt.
Kann den Frust aber verstehen.
Bedenke aber: In der Niederlage zeigt sich die wahre menschliche Größe 
:)

Wilhelm M. schrieb:
> Du hast mal wieder "vergessen"

Irrtum Wilhelm M.
Gesagt ist wohl alles.
Eher schon zu oft.
Gast #7262154
Lesenswert?

Ron T. schrieb:
> Bedenke aber: In der Niederlage zeigt sich die wahre menschliche Größe

Vielleicht....
Warum, liebster Moby, hast du schon wieder deinen Namen gewechselt?
Du weißt doch, dass du das nicht darfst.

Übrigens:
Ich gönne dir deinen kleinen Brunnen.
Bevorzuge allergings das Meer.
Gast #7262227
Lesenswert?

Wilhelm M. schrieb:
> Du lässt durch Dein Verhalten keinen anderen Schluss zu

Nimmst Du im Ernst an irgend jemand aus dem Forum wär Dir hier zu 
irgendwas verpflichtet? Hier muß sich niemand niemandem gegenüber 
rechtfertigen.
Zieh Deine Schlüsse wie Du magst.
Wundere Dich nur nicht wenn andere die ihren ziehen.
Gast #7262554
Lesenswert?

Wilhelm M. schrieb:
> In diesem Form nehme ich gar nichts an.

Das das jemand in der Ferne völlig egal sein kann scheint Dir nicht in 
den Sinn zu gelangen. Wir müssen hier nicht auf einen Nenner kommen wenn 
ein jeder mit seiner Sprache zufrieden ist und das begründet. Allerdings 
hab ich den Eindruck daß damit gewisse Leute partout nicht klarkommen. 
Die sind nämlich die eigentlich missionarischen Eiferer.

MaWin schrieb:
> Och menno! Nein, du!
> aufstampf

In diesem Sinne :)
#7262599
Lesenswert?

Ralf schrieb:
> Wilhelm M. schrieb:
>> In diesem Form nehme ich gar nichts an.
>
> Das das jemand in der Ferne völlig egal sein kann scheint Dir nicht in
> den Sinn zu gelangen.

Mit ist es egal, was Du benutzt.

> Wir müssen hier nicht auf einen Nenner kommen wenn
> ein jeder mit seiner Sprache zufrieden ist und das begründet.

Allerdings hast Du hier laut rumgetönt, das Deine Lösung in allen 
Belangen besser sei, jedoch zeigst Du das gar nicht. Auch bist Du nicht 
bereit oder in der Lage, ein Analogon zu meinem Mini-Beispiel zu 
bringen.

> Allerdings
> hab ich den Eindruck daß damit gewisse Leute partout nicht klarkommen.

Darum geht es nicht: wie schon x-mal gesagt: Du tönst rum und lieferst 
nicht.
Gast #7262657
Lesenswert?

Wilhelm M. schrieb:
> Du tönst rum und lieferst nicht

Wenn Dich mein "Geschwafel" nicht überzeugt dann überzeugt es halt 
nicht. Da bin ich völlig schmerzlos. Ich habe meine Erfahrungen gemacht, 
Du die Deinen. So wie ein jeder die seinen machen muß...

Und was heißt schon in allen Belangen besser? Das ist Asm ganz sicher 
nicht, das ist C++ ganz sicher nicht. C ist portabler- also kann Asm 
schon mal nicht in allen Belangen besser sein. Mit Unterstellungen 
bist Du aber allzu fix ganz vorn dabei. Behaupte ruhig weiter ich würde 
Code klauen, wenn Du Dein Gemüt nicht anders zügeln kannst. Das wird 
allerdings ganz sicher nicht dazu führen daß Du weiteren wunschgemäß zu 
Gesicht bekommst.
#7267838
Lesenswert?

Hallo,

habe mich versucht einzulesen. Wäre das hier äquivalent zu Wilhelms 
Code? Ist auf dem PC und CodeBlocks getestet. Deswegen die Limitierung 
auf 100 Zeilen und die 10ms Bremse. Ohne Bremse gibts Lücken in der 
Konsole, der Rechner ist zu schnell.
1
#include <chrono>
2
#include <thread>
3
#include <atomic>
4
#include <iostream>
5

6
using namespace std::this_thread;    
7
using namespace std::chrono_literals;
8
using std::chrono::system_clock;
9

10
int counter;
11

12
std::atomic<int> g;
13
std::atomic<bool> flag;
14

15
void otherThread (void)
16
{
17
  auto tempG = g.load();              // g einlesen
18
  auto tempFlag = flag.load();        // flag einlesen
19
  ++tempG;
20
  if (tempG > 9) {
21
    tempFlag = true;
22
    tempG = 0;
23
  }
24
  g.store(tempG);                     // g zurückschreiben
25
  flag.store(tempFlag);               // flag zurückschreiben
26
}
27

28
int main()
29
{
30
  std::cout << "Reset\n";
31

32
  while(1)
33
  {
34
    if (counter < 100)                  // willkürliche Ausgabenlimitierung
35
    {
36
      otherThread();
37

38
      ++counter;
39
      std::cout << "counter " << counter << " flag " << flag;
40

41
      auto tempFlag = flag.load();      // flag einlesen
42
      if (tempFlag)
43
      {
44
        tempFlag = false;
45
        flag.store(tempFlag);           // flag zurückschreiben
46
        std::cout << " Flag true.\n";
47
      }
48

49
      std::cout << "\n";
50
    }
51

52
    sleep_until(system_clock::now() + 10ms);
53
  }
54
}
#7268070
Lesenswert?

Hallo,

manchmal weiß ich nicht was dazu sagen soll ...
Worum dreht es sich denn bei mir die ganze Zeit? Das ich auf dem PC 
keinen AVR Interrupt nachbauen kann sollte doch klar sein. Der Name 
"otherThread" sollte Aussagekräftig genug sein für das Prinzip worum es 
geht.
Ich frage anders. Kann atomic.load/store deinen MemoryBarrier Aufruf 
gleichwertig ersetzen?
#7268199
Lesenswert?

Veit D. schrieb:
> Hallo,
>
> manchmal weiß ich nicht was dazu sagen soll ...

Tja, das weiß ich auch nicht.

> Worum dreht es sich denn bei mir die ganze Zeit?

Keine Ahnung.

> Das ich auf dem PC
> keinen AVR Interrupt nachbauen kann sollte doch klar sein.

Nein, ist es nicht. Ein Signal-Handler kommt dem sehr, sehr nahe.

> Der Name
> "otherThread" sollte Aussagekräftig genug sein für das Prinzip worum es
> geht.

Ja, aber Du startest eben keinen Thread. Es wäre doch ganz einfach 
gewesen,
1
std::thread t{otherThread};

einzufügen (statt otherThread() synchron aufzurufen). Und genau deswegen 
habe ich in der Art geantwortet, wie ich geantwortet habe.

> Ich frage anders. Kann atomic.load/store deinen MemoryBarrier Aufruf
> gleichwertig ersetzen?

Jein.

Am besten liest Du mal:
https://en.cppreference.com/w/cpp/atomic/atomic

Die atomics machen das load/store atomar für Dein int und bool und 
berücksichtigen das Zugriffsmodell entsprechend memory_order bspw. 
"sequential consistent", was einer allg. CPU-memory-barrier (und 
Compiler-barrier) gleichkommt. Auf x86-64 wird daraus im wesentlichen 
ein xchg, wenn die Datentypen weniger als 64Bit umfassen. Bei größeren 
DT wird dann tatsächlich ggf. ein Mutex eingebaut (etwa über einen 
Aufruf von __atomic_store).

Je nachdem was Du erreichen möchtest, wäre in Deinem Beispiel ein
1
struct Shared {
2
    int g;
3
    bool flag;
4
};
5

6
std::atomic<Shared> s;

angebrachtet gewesen. Damit wird der Zugriff auf die gesamte 
Datenstruktur atomar (was dann einem kritischen Abschnitt entspricht).

Der wesentliche Unterschied zu meinem simplen AVR Beispiel ist, dass bei 
meinem Beispiel nur der Code in main() gegen einen nebenläufigen Zugriff 
geschützt war und damit Atomarität gewährleistet hat. Der Code in der 
ISR hat das nicht gemacht / machen müssen, weil das Beispiel davon 
ausging, dass man keine weiteren Interrupt-Level (neuere AVR) benutzt.

In Deinem Beispiel könntest Du weitere Threads starten, und es wäre 
trotzdem noch ok. Sofern - wie oben gesagt - g und flag keinen 
semantischen Zusammenhang haben (nicht dieselbe Datenstruktur bilden) 
und somit der Zugriff auf beide atomar sein soll. Dann käme meine 
Modifikation (s.o.) ins Spiel.
Gast #7268216
Lesenswert?

Veit D. schrieb:
> Kann atomic.load/store deinen MemoryBarrier Aufruf
> gleichwertig ersetzen?

C++ atomics behinhalten (sogar wählbare) Memory Barriers. Ich glaube 
default war, wenn der Programmierer nichts anderes angibt, ein 
Sequence-consistent-ordering. Also das strikteste.

Vielleicht liest du endlich mal die Doku, die hier schon mehrfach 
verlinkt wurde?

https://en.cppreference.com/w/cpp/atomic/atomic

Veit D. schrieb:
> Das ich auf dem PC
> keinen AVR Interrupt nachbauen kann sollte doch klar sein.

Auch dein PC hat Threads.
Damit kann man die meisten Concurrency-Effekte von Interrupts 
hinreichend simulieren. (und noch mehr darüber hinaus)

https://en.cppreference.com/w/cpp/thread/thread

Ach ja und als Schlusswort bleibt noch zu sagen:
Vielleicht liest du endlich mal die Doku?
Gast #7268281
Lesenswert?

Veit D. schrieb:
>> Vielleicht liest du endlich mal die Doku?
>
> Was denkst du denn wie ich auf atomic load/store gekommen bin?

Du hast es ja ganz offensichtlich nicht gelesen. Denn sonst käme die 
Frage von dir nicht auf.

https://en.cppreference.com/w/cpp/atomic/atomic/store

90% des Textes dort handeln vom Memory-Barrier-Verhalten des stores.

Wichtige Lektüre, zum 100sten mal gepostet und immer noch nicht gelesen:

https://en.cppreference.com/w/cpp/atomic/memory_order
#7268618
Lesenswert?

Jan V. schrieb:
> Wilhelm M. schrieb:
>> mit der einfachen, symptomatischen Lösung zufrieden
>
> Was ist daran auszusetzen?
> Braucht es noch eine komplizierte Lösung? Mir scheint Du bist dieser
> Meinung.

Nein.
Lies Dir die Texte durch. Es ging darum aufzuzeigen, welche Schritte 
ablaufen. Einige haben nicht erkannt, was in dem ATOMIC_BLOCK()-Macro 
ablaufen.
Wenn der TO nicht daran interessiert ist zu erfahren, was die Ursachen 
für sein Problem waren, dann ist das ok für mich. Es gab aber Nachfragen 
und Bemerkungen anderer Teilnehmer.
#7268738
Lesenswert?

Hallo,

Eins werde ich nie verstehen. Das es immer wieder Leute gibt die sich 
über geäußertes Wissen aufregen. Entweder man liest still mit, man 
beteiligt sich aktiv oder man lässt alle ihr Ding machen. Aber sich 
darüber aufregen Wissen zu veröffentlichen ... dann müßte man denjenigen 
Leuten alle Bücher wegnehmen und den Schulbesuch verbieten.
Gast #7268770
Lesenswert?

Veit D. schrieb:
> Das es immer wieder Leute gibt die sich
> über geäußertes Wissen aufregen

Die Aufregung scheint mir hier eher auf zwei andere Dinge zu zielen:
- Leute wollen Dinge unbedingt komplizierter lösen als nötig
- Leute wollen Dinge diskutieren die mit dem Thread-Thema wenig zu tun 
haben
- Leute äußern sich unsachlich und völlig am Thema vorbei
#7268805
Lesenswert?

H.E. schrieb:
> Veit D. schrieb:
>> Das es immer wieder Leute gibt die sich
>> über geäußertes Wissen aufregen
>
> Die Aufregung scheint mir hier eher auf zwei andere Dinge zu zielen:
> - Leute wollen Dinge unbedingt komplizierter lösen als nötig

Du meinst sicher mich ;-)
Wenn Du meine ersten Beiträge hier gelesen hast, hast Du sicher bemerkt, 
dass ich erstmal das Problem beschrieben habe, damit der TO das 
versteht.

> - Leute wollen Dinge diskutieren die mit dem Thread-Thema wenig zu tun
> haben

Wie gesagt: der TO war höchstens an einer symptomatischen Lösung 
interessiert. Die Gründe für sein Problem haben ihn dann schon wieder 
weniger interessiert.

Und dann stiegen Leute ein, die ihm unbedingt Assembler empfehlen 
wollten ;-)
Gast #7268906
Lesenswert?

EAF schrieb:
> fürchterlich penetrant

Na na na! So kann man es auch umschreiben wenn man nichts anderes als 
unsachliche Beschimpfung zu entgegnen hat :)
Schau, die Beschränkung aufs Erforderliche entlarvt immer auch das 
Umständliche.

EAF schrieb:
> Und ob ihm ASM wirklich "kann" liegt auch im dunklen

Meinetwegen. Ich brauch Deine Bestätigung jetzt nicht wirklich.
Hauptsache mein Code tut (einfacher als bei manch anderem) was er soll.
Alles andere ist erstmal Entertainment.
#7268944
Lesenswert?

Ralf schrieb:
> Hauptsache mein Code tut (einfacher als bei manch anderem) was er soll.

Schau: Das Problem ist seit ~ 60 Jahren bekannt (Dijkstra), und genauso 
lange gibt es eine Standard-Lösung dafür. Egal ob man die in ASM, C, C++ 
oder sonstwas implementiert.

Nur weil du eine abweichende Lösung gefunden hast, die in einem ganz 
speziellen Sonderfall möglicherweise auch funktioniert, wirfst du damit 
nicht Jahrzehnte Informatik-Theorie über den Haufen.

Und wenn ein Anfänger das Problem lösen will, dann gibt man ihm erstmal 
die 08/15 - Lösung. Die funktioniert immer, unter allen Umständen, 
korrekt.

Irgendeine Spezial-Sonderfall-Lösung, mit der er beim nächsten Projekt 
auf die Nase fällt, ist da eher kontraproduktiv.

Wenn er dann den Anfänger-Status hinter sich gelassen hat, kann er 
selber entscheiden, wann er auf die IRQ-Sperre verzichten mag oder muss, 
dann braucht er aber deinen Input auch nicht mehr dafür.
#7268982
Lesenswert?

H.E. schrieb:
> Veit D. schrieb:
>> Das es immer wieder Leute gibt die sich
>> über geäußertes Wissen aufregen
>
> Die Aufregung scheint mir hier eher auf zwei andere Dinge zu zielen:
> - Leute wollen Dinge unbedingt komplizierter lösen als nötig
> - Leute wollen Dinge diskutieren die mit dem Thread-Thema wenig zu tun
> haben
> - Leute äußern sich unsachlich und völlig am Thema vorbei

Hallo,

ganz nüchtern betrachtet. Man sollte einen Schritt zurückgehen und die 
Sache neu betrachten. Was ist schlimm daran wenn jemand Wissen übern 
Tellerrand zeigt? Ob einem das persönlich zu kompliziert erscheint oder 
nicht ist immer individuell. Es ist auch erstmal egal ob man es versteht 
oder nicht. Man muss es nicht annehmen, man kann es annehmen, man kann 
es für später im Hinterstübchen behalten.
Ich programmiere Ein Kern AVRs. Andere programmieren Zwei Kern ESP32, 
andere Zwei Kern RP2040. Paar Leute werden sicherlich glücklich sein 
über die "Zusatzinformationen", statt immer nur sturr volatile.

Ich habe mich früher auch über diverse Dinge und Leute aufgeregt. 
Mittlerweile sehe ich das anders. Ich kann mich an der Stelle für mein 
vergangenes Verhalten nur Entschuldigen. War damals nicht nett von mir. 
Ich weiß das heute hoffentlich besser. Sie haben es nur gut gemeint.
Gast #7269556
Lesenswert?

Εrnst B. schrieb:
> Nur weil du eine abweichende Lösung gefunden hast, die in einem ganz
> speziellen Sonderfall möglicherweise auch funktioniert,

Wie amüsant.
Übrigens Ernst, da waren noch ein paar Fragen an Dich offen :)

EAF schrieb:
> Ach der Frosch, in seinem AVR-ASM Brunnen, er quakt noch!
> Wie schön ...

Auf dieses Niveau muss man sich wirklich nicht hinab begeben. Quake 
fröhlich weiter, zu mehr langts offensichtlich nicht mehr :(

Veit D. schrieb:
> Ich kann mich an der Stelle für mein vergangenes Verhalten nur
> Entschuldigen. War damals nicht nett von mir.

Sollte das eine Vorlage für mich sein?
Da kann ich mich aber nur entschuldigen daß ich dazu keinerlei Anlass 
sehe.

MaWin schrieb:
> Du hast es ja ganz offensichtlich nicht gelesen.
> Wichtige Lektüre, zum 100sten mal gepostet und immer noch nicht gelesen

Also Veit D., es warten weit wichtigere Aufgaben auf Dich. Vor dem 
Aufwand, diese Bürokratie in sich reinzuprügeln würde ich aber immer 
empfehlen, zunächst das Problem zu analysieren, ob es nicht einfachere 
Wege gibt?!
Beitrag #7269998 wurde von einem Moderator gelöscht.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren