Forum: Mikrocontroller und Digitale Elektronik Datenkonflikt: wie heißt das gleich wieder?


von einRobert (Gast)


Lesenswert?

Hallo,

das Problem: im 'normalen' Programm und in einer Interruptroutine
wird auf die selbe Variable zugegriffen. Wie kann man Probleme
vermeiden bzw welche Suchbegriffe brauchts für Google.

Danke :)

von Dominik S. (dasd)


Lesenswert?

volatile

von Peter II (Gast)


Lesenswert?

Dominik S. schrieb:
> volatile

nö

der zugriff muss atomar sein oder synchronisiert werden.

von K.B. (Gast)


Lesenswert?

Semaphore?

von (prx) A. K. (prx)


Lesenswert?

Eines der Zauberworte wäre "Interrupt Enable Flag".

Semaphoren im Interrupt?
Wie "synchronisiert"?
Immerhin, "atomar" passt.

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

A. K. schrieb:
> Eines der Zauberworte wäre "Interrupt Enable Flag".

woher kennst du seine Hardware, ob sie so etwas hat?

> Semaphoren im Interrupt?
warum nicht?

> Wie "synchronisiert"?
kann man erst beantworten wenn man die Hardware und Software kennt.

von Dominik S. (dasd)


Lesenswert?

Peter II schrieb:
> nö

einRobert schrieb:
> Wie kann man Probleme vermeiden

Du willst mir also erzählen, dass der Einsatz des 
"volatile"-Schlüsselworts im gegebenen Fall keine Probleme vermeiden 
kann?
Angenommen natürlich er nutzt C (wovon man wohl ausgehen kann).

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Dominik S. schrieb:
> "volatile"-Schlüsselworts im gegebenen Fall keine Probleme vermeiden
> kann?

ja will ich.

Volatile macht etwas komplett anders. Es ist nur ein Hinweis für den 
Compiler das die Variabel sind ändern kann ohne das er es "sieht". Viel 
mehr Probleme macht aber die Zugriff auf die Variabel wenn er nicht 
Atomar oder Anders abgesichert wird. Und daran ändert Volatile nicht.

Wenn man weiß was man macht, kommt man auch ohne Volatile aus.

von Max G. (l0wside) Benutzerseite


Lesenswert?

Suchst du das Wort Mutex?

Max

von Daniel V. (danvet)


Lesenswert?

Peter II schrieb:

> Wenn man weiß was man macht, kommt man auch ohne Volatile aus.

Das bezweifle ich.

von kopfkratzer (Gast)


Lesenswert?

kopfkratz
Passende Stichworte wurden ja schon genannt.
Die einfachste Variante ist in der IRQ zusätzlich ein (volatile) Flag zu 
setzen das in der Hauptroutine anzeigt das gerade ein IRQ zugeschlagen 
hat und danach entscheidet wie man mit der nun durch IRQ veränderten 
Variable umgeht.

von Peter II (Gast)


Lesenswert?

Daniel V. schrieb:
> Das bezweifle ich.

kannst du ja gerne machen. (die dümmste uns einfachste Lösung ist den 
optimier abzuschalten)

von Reinhard Kern (Gast)


Lesenswert?

Hazard, Race Condition, Dead Lock...

Gruss Reinhard

von Daniel V. (danvet)


Lesenswert?

Peter II schrieb:
> Daniel V. schrieb:
>> Das bezweifle ich.
>
> kannst du ja gerne machen. (die dümmste uns einfachste Lösung ist den
> optimier abzuschalten)

und die klügste?

von (prx) A. K. (prx)


Lesenswert?

Peter II schrieb:
>> Semaphoren im Interrupt?
> warum nicht?

Und was machst du in dem Interrupt, wenn die Sema schon vergeben ist? 
Warteschleife? Yield? ;-)

Ok, es kann Szenarios geben, wo es möglich ist, im Interrupt ggf. nicht 
drauf zuzugreifen. Aber meistens hat man keine Wahl.

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Daniel V. schrieb:
> und die klügste?
die wird es nicht geben.

die Abfrage in eine Funktion stecken die in einer andern C Datei liegt, 
oder die Funktion als noinline Kennzeichnen.
Dann kann der Compiler die Variabel nicht in einem Register vorhalten. 
(Das sind aber mehr oder weniger hacks, um die langsamkeit beim zugriff 
in der ISR auf eine volatile variabel zu verhindern)

von Daniel V. (danvet)


Lesenswert?

Peter II schrieb:
> (Das sind aber mehr oder weniger hacks, um die langsamkeit beim zugriff
> in der ISR auf eine volatile variabel zu verhindern)

Wenns dir nur darum geht, dann kannst du doch die volatile variable in 
der ISR ins register laden und mit dem register arbeiten.

was machst du mit?:

1
volatile uint16 counter;
2
3
ISR()
4
{
5
6
 if(counter)
7
 {
8
 counter--;
9
 }
10
11
}
12
13
void main()
14
{
15
 _disable_interrupt();
16
 counter = 1000;
17
 _enable_interrupt();
18
 while(counter);
19
20
}

von (prx) A. K. (prx)


Lesenswert?

Peter II schrieb:
> die Abfrage in eine Funktion stecken die in einer andern C Datei liegt,
> oder die Funktion als noinline Kennzeichnen.
> Dann kann der Compiler die Variabel nicht in einem Register vorhalten.

Auf solche Ringkämpfe zwischen Programmierer und Compiler sollte man 
sich in produktivem Code besser nicht einlassen. Die erste Variante 
scheitert, wenn alles ein einem Rutsch übersetzt wird, was heute nicht 
mehr so selten ist. Noinline wiederum ist eine proprietäre Eigenheit vom 
GCC.

von Peter II (Gast)


Lesenswert?

was machst du mit?:

[/c]
uint16 counter;

uint16 _attribute_ ((noinline)) GetCounter()
{
   return counter;
}

ISR()
{

 if(counter)
 {
 counter--;
 }

}

void main()
{
 _disable_interrupt();
 counter = 1000;
 _enable_interrupt();
 while( GetCounter() );

}
[/c]


Ich würde aber danach dem ASM code anschauen.

von (prx) A. K. (prx)


Lesenswert?

Bei einem 8-Bit Prozessor wirst du damit nicht glücklich. Und bei einem 
Prozessor mit mindestens 16 Bits ist
  counter = 1000;
wohl stets atomar, bezogen auf den Zugriff auf counter.

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

A. K. schrieb:
> Bei einem 8-Bit Prozessor wirst du damit nicht glücklich. Und bei einem
> Prozessor mit mindestens 16 Bits ist
>   counter = 1000;
> wohl stets atomar.

es geht ja nicht ums Atomar, sondern um das volatile. (was man also hack 
so einsparen kann)

von Dominik S. (dasd)


Lesenswert?

Einigen wir uns einfach darauf das Peter ganz viele tolle "hacks" kennt, 
die man aber eigentliche nicht braucht, wenn man stattdessen einfach das 
- dafür vorgesehene - Schlüsselwort volatile benutzt ^^

von Peter II (Gast)


Lesenswert?

Dominik S. schrieb:
> Einigen wir uns einfach darauf das Peter ganz viele tolle "hacks" kennt,
> die man aber eigentliche nicht braucht, wenn man stattdessen einfach das
> - dafür vorgesehene - Schlüsselwort volatile benutzt ^^

klar kann man es auch immer so machen wie es jeder macht - nur kann man 
damit nicht das Optimum rausholen.

Sonst würde solche schönen dinge wie 
http://de.wikipedia.org/wiki/Duff%E2%80%99s_Device nicht entstehen.

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:
> Dominik S. schrieb:
>> Einigen wir uns einfach darauf das Peter ganz viele tolle "hacks" kennt,
>> die man aber eigentliche nicht braucht, wenn man stattdessen einfach das
>> - dafür vorgesehene - Schlüsselwort volatile benutzt ^^
>
> klar kann man es auch immer so machen wie es jeder macht - nur kann man
> damit nicht das Optimum rausholen.

Wieso nicht?

Wenn das volatile, wegen Mehrfachbenutzung der Variablen in der Schleife 
stört, kann man immer noch innerhalb der Schleife eine Hilfsvariable 
benutzen, in der man sich erst mal eine Kopie von der volatile Variablen 
für diesen einen Schleifendurchgang zieht.

Dein 'Hack' beruht ja im Grunde auch nur darauf, dem Optimizer soviele 
Prügel zwischen die Beine zu werfen, so dass er diesen Teil nicht mehr 
optimieren kann. Ich seh da jetzt nicht wirklich einen Vorteil gegenüber 
volatile. Ganz im Gegenteil wurde volatile in die Sprache mit 
aufgenommen, eben weil derartige Hacks durch Fortschritte in den 
Optimizern immer unzuverlässiger wurden.

> Sonst würde solche schönen dinge wie
> http://de.wikipedia.org/wiki/Duff%E2%80%99s_Device nicht entstehen.

Ist aber eine andere Baustelle.

von Peter II (Gast)


Lesenswert?

Karl Heinz schrieb:
> Dein 'Hack' beruht ja im Grunde auch nur darauf, dem Optimizer soviele
> Prügel zwischen die Beine zu werfen, so dass er diesen Teil nicht mehr
> optimieren kann. Ich seh da jetzt nicht wirklich einen Vorteil gegenüber
> volatile.

ich habe nur ein kleine Problem damit, das das volatile den erzeugten 
code in der ISR ändert, obwohl dort überhaupt kein bedarf dafür besteht 
und dort aber oft eine hohe Geschwindigkeit gewünscht ist.

Nur weil die C leute sind nicht bessere als ein volatile einfallen 
lassen haben heißt das noch lange nicht das es immer die beste Lösung 
ist.

Ich wüste auch nicht wie man es einfach und besser machen kann.

von Random .. (thorstendb) Benutzerseite


Lesenswert?

Dominik S. schrieb:
> Einigen wir uns einfach darauf das Peter ganz viele tolle "hacks" kennt,
> die man aber eigentliche nicht braucht, wenn man stattdessen einfach das
> - dafür vorgesehene - Schlüsselwort volatile benutzt ^^

Also ...
"volatile" ist nur eine Kennzeichnung für den Compiler, dass die 
Variable auch woanders (also nicht durch den normalen Codeablauf, z.B. 
in einer ISR oder einer anderen Task) geändert werden kann, und dass der 
Compiler die daher nicht komplett durchoptimieren (oder rauswerfen) 
darf.

Der Zugriff von beiden Seiten muss gesichert werden, z.B. "atomic 
instruction", damit der upper / lower half Zugriff nicht von einem 
Schreibzugfriff dazwischen gestört wird.
Oder - wenn es um ganze Datensätze geht, kann man mehrere Buffer (double 
buffering, Queue) verwenden.

von (prx) A. K. (prx)


Lesenswert?

Karl Heinz schrieb:
> Dein 'Hack' beruht ja im Grunde auch nur darauf, dem Optimizer soviele
> Prügel zwischen die Beine zu werfen, so dass er diesen Teil nicht mehr
> optimieren kann.

Nicht ganz. Die Zugriffe innerhalb der ISR sind optimierbar. Sein Hack 
erspart es, die Variable in der ISR in eine lokale Variable 
umzukopieren.

von Fred (Gast)


Lesenswert?

Dominik S. schrieb:
> Einigen wir uns einfach darauf das Peter ganz viele tolle "hacks" kennt,
> die man aber eigentliche nicht braucht, wenn man stattdessen einfach das
> - dafür vorgesehene - Schlüsselwort volatile benutzt ^^

Nein, das ist falsch.

volatile reicht nicht aus, auch wenn das hier immer gerne behauptet 
wird.

Auf vielen uc-Plattformen mag das sogar klappen, aber allgemein ist das 
falsch.

Eine ordentliche Synchronisation ist vonnöten. Gegebenenfalls inklusive 
memory barriers.

von (prx) A. K. (prx)


Lesenswert?

Wenn wir noch ein wenig weiter machen, dann sind wir bei Intels 
Transactional Memory und der Fragesteller, der vielleicht einen AVR 
meinte, hält uns für völlig gaga. ;-)

von Stefan E. (sternst)


Lesenswert?

Peter II schrieb:
> ich habe nur ein kleine Problem damit, das das volatile den erzeugten
> code in der ISR ändert, obwohl dort überhaupt kein bedarf dafür besteht
> und dort aber oft eine hohe Geschwindigkeit gewünscht ist.

Und was ist jetzt genau das Problem daran, in der ISR einfach eine 
lokale nicht-volatile Variable zu verwenden?

von Peter II (Gast)


Lesenswert?

Stefan Ernst schrieb:
> Und was ist jetzt genau das Problem daran, in der ISR einfach eine
> lokale nicht-volatile Variable zu verwenden?

keines, es ist nur langsamer also ohne die Variable. Und man muss es 
wissen und machen. Man muss also wieder selber optimieren, obwohl immer 
gesagt wird der Compiler macht das schon.

von Dominik S. (dasd)


Lesenswert?

Fred schrieb:
> Nein, das ist falsch.
>
> volatile reicht nicht aus, auch wenn das hier immer gerne behauptet
> wird.

Ich habe nicht behauptet, dass "volatile" irgendwelche Probleme 
bezüglich nicht-atomaren Zugriffen oder Synchronisierung löst.

Der TO fragte ganz oben nach Mitteln, um Probleme zu vermeiden, wenn:

>im 'normalen' Programm und in einer Interruptroutine
>wird auf die selbe Variable zugegriffen.

Und "volatile" ist da nun mal eine der richtigen Antworten.
Ich sagte nie, dass es die Lösung für alle Probleme ist.

Fred schrieb:
>> Einigen wir uns einfach darauf das Peter ganz viele tolle "hacks" kennt,
>> die man aber eigentliche nicht braucht, wenn man stattdessen einfach das
>> - dafür vorgesehene - Schlüsselwort volatile benutzt ^^

Bezog sich lediglich auf Peters Anstrengungen volatile auf alle Fälle zu 
vermeiden.
Nicht auf das Thema Variablen im Interrupt an sich.

von Stefan E. (sternst)


Lesenswert?

Peter II schrieb:
> keines, es ist nur langsamer also ohne die Variable.

Bitte? Da musst du mir jetzt mal erklären, was daran langsamer sein 
soll.

von Peter II (Gast)


Lesenswert?

Stefan Ernst schrieb:
> Peter II schrieb:
>> keines, es ist nur langsamer also ohne die Variable.
>
> Bitte? Da musst du mir jetzt mal erklären, was daran langsamer sein
> soll.

glaubst du kopieren und Register gib es kostenlos in der ISR?

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:

> Man muss also wieder selber optimieren, obwohl immer gesagt
> wird der Compiler macht das schon.

Im Zweifel ist mir aber ein funktionierendes Progamm lieber, auch wenn 
es einen Tick langsamer ist als ein um einen Tick schnelleres Programm, 
welches falsche Ergebnisse bringt.

von Peter II (Gast)


Lesenswert?

Karl Heinz schrieb:
> Im Zweifel ist mir aber ein funktionierendes Progamm lieber, auch wenn
> es einen Tick langsamer ist als ein um einen Tick schnelleres Programm,
> welches falsche Ergebnisse bringt.

und wenn es nicht funktioniert weil es zu langsam ist?

Es gibt nicht immer nur eine Lösung!

von Stefan E. (sternst)


Lesenswert?

Peter II schrieb:
> glaubst du kopieren und Register gib es kostenlos in der ISR?

Nichts von dem wird zusätzlich benötigt. In beiden Fällen wird die 
Variable in Register geladen. Nur dass halt einmal die Register 
"namenlos" sind, und im anderen Fall repräsentieren sie die lokale 
Variable.

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:
> Stefan Ernst schrieb:
>> Peter II schrieb:
>>> keines, es ist nur langsamer also ohne die Variable.
>>
>> Bitte? Da musst du mir jetzt mal erklären, was daran langsamer sein
>> soll.
>
> glaubst du kopieren und Register gib es kostenlos in der ISR?

Das Argument zieht jetzt aber nicht.
Denn wenn dem Compiler in der ISR die Register ausgehen, dann muss er 
auch deine nicht-volatile Variable nachladen.
Im Zweifel kann man immer noch mit einem nicht-volatile konstantem 
Pointer, welcher die Adresse der Variablen hält, das volatile innerhalb 
der ISR "wegcasten" und sie innerhalb der ISR damit der normalen 
Datenflussanalyse zuführen.

von Peter II (Gast)


Lesenswert?

Stefan Ernst schrieb:
> Peter II schrieb:
>> glaubst du kopieren und Register gib es kostenlos in der ISR?
>
> Nichts von dem wird zusätzlich benötigt. In beiden Fällen wird die
> Variable in Register geladen. Nur dass halt einmal die Register
> "namenlos" sind, und im anderen Fall repräsentieren sie die lokale
> Variable.

kann man nicht pauschal sagen, kommt auf Hardware an. Es gibt auch 
Hardware die vergleiche direkt im RAM machen kann. Damit ist das 
kopieren zusätzliche Arbeit.

von Peter II (Gast)


Lesenswert?

Karl Heinz schrieb:
> Das Argument zieht jetzt aber nicht.
> Denn wenn dem Compiler in der ISR die Register ausgehen, dann muss er
> auch deine nicht-volatile Variable nachladen.

bei einem Atmel ja. Aber wir haben uns noch nicht auf eine Hardware 
festgelegt.

von Karl H. (kbuchegg)


Lesenswert?

Peter II schrieb:
> Karl Heinz schrieb:
>> Das Argument zieht jetzt aber nicht.
>> Denn wenn dem Compiler in der ISR die Register ausgehen, dann muss er
>> auch deine nicht-volatile Variable nachladen.
>
> bei einem Atmel ja. Aber wir haben uns noch nicht auf eine Hardware
> festgelegt.

Wir haben uns auch nicht auf einen Compiler festgelegt.
1
uint16 _attribute_ ((noinline)) GetCounter() {

: Bearbeitet durch User
von Sebastian W. (wangnick)


Lesenswert?


von (prx) A. K. (prx)


Lesenswert?

Peter II schrieb:
> kann man nicht pauschal sagen, kommt auf Hardware an. Es gibt auch
> Hardware die vergleiche direkt im RAM machen kann. Damit ist das
> kopieren zusätzliche Arbeit.

Zusätzlicher Code ja, zusätzliche Register evtl. ja, bei zusätzlicher 
Arbeit wird es komplizierter. Laden muss der Prozessor das Zeug in 
beiden Fällen, da es nicht der Speicher selbst ist, der den Vergleich 
durchführt, sondern der Prozessor. In Registern. Nur sind das ggf. 
temporäre unbenannte Register.

: Bearbeitet durch User
von Fred (Gast)


Lesenswert?

Dominik S. schrieb:
> Und "volatile" ist da nun mal eine der richtigen Antworten.

Nein. volatile läßt die Race-Condition nicht verschwinden.

Schau, du kannst die Augen so fest zudrücken, wie du willst. Die 
Realität ändert sich dadurch aber nicht.

von (prx) A. K. (prx)


Lesenswert?

Wenn wir mal das obige Beispiel betrachten:
  if(counter)
    counter--;

Bei einer CISC wie x86/68000/M16C, also jeder Klasse von Maschinen, die 
mit dem Speicher direkt arbeiten können, wird bei einer volatilen 
Variable daraus:
  test counter
  breq ...
  dec counter
was sich im internen Ablauf so darstellt:
  load temp, counter
  test temp
  breq ...
  load temp, counter
  dec temp
  store temp, counter

Mit der Umgehung über eine lokale Variable, also
  unsigned t = counter;
  if (t)
     counter = t - 1;
wird im Output und im Ablauf daraus das, was RISC auch macht:
  load r0, counter
  test r0 (evtl. Teil von load oder von breq)
  breq ... (entfällt u.U. bei ARM)
  dec r0
  store r0 counter
was zwar mehr Befehle sind, daher langsamer sein kann, aber weniger 
Operationen, daher schneller sein kann. Und hat ein Load weniger, was je 
nach Prozessor viel ausmachen kann.

: Bearbeitet durch User
von c-hater (Gast)


Lesenswert?

A. K. schrieb:

> Und was machst du in dem Interrupt, wenn die Sema schon vergeben ist?
> Warteschleife? Yield? ;-)

Na klar, Yield, natürlich, was denn sonst?.

Die einzige Voraussetzung, damit das funktioniert, ist, daß praktisch 
sämtlicher Code im System (Startup und Sleep-Kram ausgenommen, das 
entspricht dem Idle-Task) ebenfalls in Folge von Interrupts durchlaufen 
wird, also ein Timer-Interrupt als Antrieb eines Task-Schedulers agiert. 
Also ziemlich genau das übliche Vorgehen beim Multitasking...

Und es ist auch garnicht mal so schwierig zu programmieren. Es lauft 
darauf hinaus, auch ISRs nach Abarbeitung ihrer exclusiv zu erledigenden 
Aufgaben zu einem normalen Task (wenn auch mit hoher Priorität) zu 
machen und ihren weiteren Ablauf der Kontrolle des Schedulers zu 
unterwerfen wie jeden anderen Task auch.

Allerdings ist so eine Lösung als Gesamtsystem, wie jedes 
funktionierende MT-OS, relativ ineffizient. Bei kleinen Controllern mit 
nur sehr wenigen und bezüglich ihrer Aufgabe sehr überschaubaren "Tasks" 
durchdenkt man besser die Interaktionen detailliert und gestaltet sie 
so, daß die Synchronisationsmechanismen eines universellen MT-OS erst 
garnicht nötig werden.
Welches übrigens das Problem der Notwendigkeit des Durchdenkens der 
möglichen Interaktionen "parallelen" Codes sowieso auch nur verringern, 
aber nicht überflüssig machen würde. Siehe die wohlbekannte 
Deadlock-Problematik.

Im Kern übrigens nix anderes, als das, auf was du hinaus wolltest. Auch 
nur ein Deadlock. Stell' dir die Möglichkeit zur Ausführung von Code 
einfach abstrakt als eine durch einen Mutex geschützte Resource vor. 
Dann bist du unmittelbar beim ganz normalen Wahnsinn paralleler 
Programmierung, ganz genau entsprechend der reinen Lehre. Und natürlich 
entsprechend aufzulösen.

von X-X (Gast)


Lesenswert?

einRobert schrieb:
> Wie kann man Probleme
> vermeiden bzw welche Suchbegriffe brauchts für Google.

Welche Probleme willst du denn vermeiden? in welcher Sprache bei welchem 
Compiler auf welcher Hardware?

Wenn es darum einen ISR Call mit refresh der Variablen zu signalisieren 
reicht ein Flag. Wenn mehrfachISRs abgefangen werden sollen halt n 
Zähler).

Das ist mega-portabel. Geht in jeder Sprache auf jeder Hardware und mit 
jedem compiler.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.