Forum: Mikrocontroller und Digitale Elektronik Warum sind lokale Variablen reentrant


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Johannes H. (Gast)


Bewertung
-2 lesenswert
nicht lesenswert
Hallo Leute,

wie schon im Betreff schon angegeben ist meine Frage weshalb lokale 
Variablen reentrant sind? Ich weiß, dass lok. Variablen im Stack 
abgespeichert werden.

Lg

von batman (Gast)


Bewertung
2 lesenswert
nicht lesenswert
Variablen sind nicht reentrant. Da bringst du was durcheinander.

von Hmmm (Gast)


Bewertung
2 lesenswert
nicht lesenswert
Der Platz auf dem Stack wird zu Beginn der Funktion durch Anpassung des 
Stack Pointers reserviert. Wenn die Funktion sich jetzt selbst aufruft, 
passiert dasselbe nochmal, beide Instanzen haben also ihre eigenen 
Bereiche auf dem Stack und kommen sich nicht in die Quere.

In Multithreading-Umgebungen funktioniert das ebenfalls, weil jeder 
Thread seinen eigenen Stack hat.

Bei globalen Variablen wiederum greifen beide Instanzen auf denselben 
Speicher zu, was Reentranz-Probleme mit sich bringen kann.

von Lothar M. (lkmiller) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Johannes H. schrieb:
> weshalb lokale Variablen reentrant sind?
Funktionen sind reentrant, weil ein wiederholter/rekursiver Aufruf der 
Funktion andere Speicherplätze für "normale" lokale Variablen auf dem 
Stack belegt.
Statische lokale Variablen werden allerdings nur 1x angelegt. Eine 
Funktion mit solchen Variablen hat also durchaus Seitenwirkungen...

Siehe z.B. http://codepad.org/O3QFFd5D

von Pandur S. (jetztnicht)


Bewertung
0 lesenswert
nicht lesenswert
lokale variablen sind deshalb brauchbar in einer parallel aufrufbaren 
Funktion, weil sie immer neu sind. Jeder Aufruf der Funktion hat seinen 
eigenen Satz an lokalen Variablen.

von (prx) A. K. (prx)


Bewertung
0 lesenswert
nicht lesenswert
Johannes H. schrieb:
> wie schon im Betreff schon angegeben ist meine Frage weshalb lokale
> Variablen reentrant sind?

Ob Funktionen mit ihren Parametern und "auto" Variablen reentrant sind 
oder nicht, wird zunächst von der Programmiersprache definiert. Und C 
definiert das so, also ist das in vollständig konformen 
Implementierungen auch so.

Es gibt allerdings Hardware, die sich damit etwas schwer tut. Etwa wenn 
sie mangels entsprechender Adressiermöglichkeit statische Daten 
wesentlich leichter ansprechen kann, als Daten auf einem Stack (8051, 
8-Bit PICs unterhalb der erweiterten PIC18). Da kann es sein, dass 
Funktionen nur auf ausdrücklichen Wunsch reentrant sind.

: Bearbeitet durch User
von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Da kann es sein, dass Funktionen nur auf
> ausdrücklichen Wunsch reentrant sind (8051, 8-Bit PICs).

Ja, der Keil C51 erstellt einen Calling-tree und überlagert Variablen. 
Das ergibt einen deutlich kompakteren Code gegenüber Push/Pop-Orgien, da 
er die meisten Operationen direkt im SRAM ausführen kann. Das ist aber 
kein Nachteil, da reentrante Funktionen nur sehr selten benötigt werden.

von Johannes H. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für die Antworten. Angenommen ich arbeite in einer 
Echtzeitumgebung, in der zwei Tasks auf eine Funktion zugreifrn.
1
 voif func_test( int x, int y)

Wenn jetzt der nieder priorer Task mitten in der Funktion durch den 
höhrer prioren Task preempted wird, werden die Variablen x und y im 
Stack vom nieder prioren Task gespeichert und sobald dieser Task wieder 
CPU zeit erhält werden diese vom Stack geladen und der Task setzt seine 
Arbeit in der Funktion fort?

Liege ich da richtig?

von (prx) A. K. (prx)


Bewertung
0 lesenswert
nicht lesenswert
Johannes H. schrieb:
> Liege ich da richtig?

Da du offenbar Multitasking meinst: In einem Betriebssystem oder RTOS 
hat jede Task ihren eigenen Stack und ihre eigenen Registerinhalte. 
Deshalb entsteht kein Konflikt.

: Bearbeitet durch User
von Axel S. (a-za-z0-9)


Bewertung
0 lesenswert
nicht lesenswert
Johannes H. schrieb:
> Vielen Dank für die Antworten. Angenommen ich arbeite in einer
> Echtzeitumgebung, in der zwei Tasks auf eine Funktion zugreifrn.
>
>
1
 voif func_test( int x, int y)
>
> Wenn jetzt der nieder priorer Task mitten in der Funktion durch den
> höhrer prioren Task preempted wird, werden die Variablen x und y im
> Stack vom nieder prioren Task gespeichert und sobald dieser Task wieder
> CPU zeit erhält werden diese vom Stack geladen und der Task setzt seine
> Arbeit in der Funktion fort?
>
> Liege ich da richtig?

Nicht so ganz. Sobald einer der beiden Threads (egal welcher) die 
Funktion aufruft, werden die lokalen Variablen der Funktion (die du hier 
gar nicht gezeigt hast; du redest nur von den Funktionsparametern, was 
wieder etwas anderes ist) auf dem Stack des gerade laufenden Threads 
angelegt. Und da jeder Thread seinen eigenen Stack(bereich) hat, kommen 
sie sich nicht in die Quere.

Bei einem Taskwechsel werden auch keine lokalen Variablen hin und her 
geschoben, sondern es wird der Stackpointer der CPU auf den gültigen 
Wert für den neuen Thread gesetzt. Da Variablen auf dem Stack relativ 
zum Stackpointer adressiert werden, findet der neue Thread seine lokalen 
Variablen wieder am gleichen Offset wie vorher.

Funktionsparameter werden entweder in Registern übergeben - da werden 
sie bei einem Taskwechsel zusammen mit allen alderen Registern mit 
weggesichert. Oder sie werden auf dem Stack übergeben und dann gilt das 
oben gesagte.

von (prx) A. K. (prx)


Bewertung
0 lesenswert
nicht lesenswert
Axel S. schrieb:
> Nicht so ganz. Sobald einer der beiden Threads (egal welcher) die
> Funktion aufruft, werden die lokalen Variablen der Funktion (die du hier
> gar nicht gezeigt hast; du redest nur von den Funktionsparametern, was
> wieder etwas anderes ist) auf dem Stack des gerade laufenden Threads
> angelegt.

Register werden beim Taskwechsel nicht notwendigerweise auf dem Stack 
abgelegt. Das kann auch woanders sein.

von Johannes H. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Axel S. schrieb:
> Funktionsparameter werden entweder in Registern übergeben - da werden
> sie bei einem Taskwechsel zusammen mit allen alderen Registern mit
> weggesichert. Oder sie werden auf dem Stack übergeben und dann gilt das
> oben gesagte.

Das heißt, wenn ich meiner Funktion die Parameter call-by-value 
übergebe(wie in dem obigen Beispiel), dann ist es sichergestellt, dass 
sich die Tasks nicht in die Quere kommen?

Heißt das, dass Register auch individuell gespeichert werden? (Bezogen 
auf Tasks)

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
Sie kommen sich nicht in die Quere.

Wie das im Detail abgehandelt wird, ist Systemabhängig.
Und sollte damit nur den Systemprogrammierer interessieren.
Der Anwendungsprogrammierer muss sich nicht damit belasten.

von (prx) A. K. (prx)


Bewertung
0 lesenswert
nicht lesenswert
Johannes H. schrieb:
> Heißt das, dass Register auch individuell gespeichert werden? (Bezogen
> auf Tasks)

Ja.

von Johannes H. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ok und wie schaut das aus wenn ich die Parameter call-by-reference 
übergebe? Dann ist meine Funktion nicht mehr reentrant oder?

von (prx) A. K. (prx)


Bewertung
0 lesenswert
nicht lesenswert
Johannes H. schrieb:
> Ok und wie schaut das aus wenn ich die Parameter call-by-reference
> übergebe? Dann ist meine Funktion nicht mehr reentrant oder?

Das hängt nicht von der Funktion ab. Übergeben werden dann die Adressen 
von den Parametern per call by value. Was dahinter steht ist der 
Funktion selbst egal. Sind es Adressen von verschiedenen Variablen, gibt 
es kein Problem. Sind sie gleich, dann schon.

: Bearbeitet durch User
von Axel S. (a-za-z0-9)


Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Axel S. schrieb:
>> Sobald einer der beiden Threads (egal welcher) die
>> Funktion aufruft, werden die lokalen Variablen der Funktion (die du hier
>> gar nicht gezeigt hast; du redest nur von den Funktionsparametern, was
>> wieder etwas anderes ist) auf dem Stack des gerade laufenden Threads
>> angelegt.
>
> Register werden beim Taskwechsel nicht notwendigerweise auf dem Stack
> abgelegt.

Huch. Wo soll ich das behauptet haben?

von round robin (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wie sieht es denn mit local statics aus? Und Tschüss reentrant. ;-)

von Carl D. (jcw2)


Bewertung
0 lesenswert
nicht lesenswert
Peter D. schrieb:
> A. K. schrieb:
>> Da kann es sein, dass Funktionen nur auf
>> ausdrücklichen Wunsch reentrant sind (8051, 8-Bit PICs).
>
> Ja, der Keil C51 erstellt einen Calling-tree und überlagert Variablen.
> Das ergibt einen deutlich kompakteren Code gegenüber Push/Pop-Orgien, da
> er die meisten Operationen direkt im SRAM ausführen kann. Das ist aber
> kein Nachteil, da reentrante Funktionen nur sehr selten benötigt werden.

Man könnte bei solchen Architekturen (wie x51), die absolute 
Adressierung "bevorzugen" und reentranten Funktionen mit vielen 
Zugriffen auf lokale Variablen, diese wie Statische ablegen und nur am 
Anfang/Ende diese am Stück auf/von den(/einen) (Software/)Stack 
sichern/zurückladen. Solange x51 ein Single-Core bleibt ;-)
Und ob sich der Aufwand lohnt, bei der Konkurrenz der 32Bitter, ist 
natürlich eine andere Frage.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.