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
Variablen sind nicht reentrant. Da bringst du was durcheinander.
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.
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
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.
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
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.
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?
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
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.
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.
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)
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.
Johannes H. schrieb: > Heißt das, dass Register auch individuell gespeichert werden? (Bezogen > auf Tasks) Ja.
Ok und wie schaut das aus wenn ich die Parameter call-by-reference übergebe? Dann ist meine Funktion nicht mehr reentrant oder?
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
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?
Wie sieht es denn mit local statics aus? Und Tschüss reentrant. ;-)
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.