[C++] Was genau ist eine Wiedereintrittsfunktion?


Answers

"Sicher" ist genau so definiert, wie der gesunde Menschenverstand es vorschreibt - es bedeutet "sein Ding richtig zu machen, ohne andere Dinge zu stören". Die sechs Punkte, die Sie anführen, drücken ganz klar die Anforderungen aus, um dies zu erreichen.

Die Antworten auf Ihre 3 Fragen sind 3 × "Nein".

Sind alle rekursiven Funktionen reentrant?

NEIN!

Zwei simultane Aufrufe einer rekursiven Funktion können sich leicht gegenseitig stören, wenn sie beispielsweise auf dieselben globalen / statischen Daten zugreifen.

Sind alle thread-sicheren Funktionen reentrant?

NEIN!

Eine Funktion ist threadsicher, wenn sie bei gleichzeitigem Aufruf nicht stört. Dies kann z. B. erreicht werden, indem ein Mutex verwendet wird, um die Ausführung des zweiten Aufrufs zu blockieren, bis der erste Aufruf beendet ist, so dass nur ein Aufrufvorgang gleichzeitig ausgeführt wird. Reentrancy bedeutet gleichzeitig ausgeführt werden, ohne andere Aufrufe zu stören .

Sind alle rekursiven und threadsicheren Funktionen reentrant?

NEIN!

Siehe oben.

Question

Most Fällen wird die Definition von Reentrance aus Wikipedia zitiert:

Ein Computerprogramm oder eine Routine wird als Wiedereintritt beschrieben, wenn sie sicher wieder aufgerufen werden kann, bevor ihr vorheriger Aufruf abgeschlossen wurde (dh sie kann gleichzeitig sicher ausgeführt werden). Um wiedereinzutreten, ein Computerprogramm oder eine Routine:

  1. Muss keine statischen (oder globalen) nicht konstanten Daten enthalten.
  2. Die Adresse darf nicht an statische (oder globale) nicht konstante Daten zurückgegeben werden.
  3. Muss nur an den Daten arbeiten, die ihm vom Anrufer zur Verfügung gestellt wurden.
  4. Sie dürfen sich nicht auf Sperren für Singleton-Ressourcen verlassen.
  5. Darf seinen eigenen Code nicht ändern (es sei denn, er wird in einem eigenen Thread-Speicher ausgeführt)
  6. Darf keine nicht-reentranten Computerprogramme oder Routinen aufrufen.

Wie ist sicher definiert?

Wenn ein Programm gleichzeitig sicher ausgeführt werden kann , bedeutet es immer, dass es sich um ein neues Programm handelt?

Was genau ist der rote Faden zwischen den sechs genannten Punkten, die ich bei der Überprüfung meines Codes für Wiedereintrittsfunktionen beachten sollte?

Ebenfalls,

  1. Sind alle rekursiven Funktionen reentrant?
  2. Sind alle thread-sicheren Funktionen reentrant?
  3. Sind alle rekursiven und threadsicheren Funktionen reentrant?

Beim Schreiben dieser Frage fällt mir eines ein: Sind die Begriffe Wiedereintritt und Gewindesicherheit überhaupt absolut, dh haben sie feste Definitionen? Denn, wenn sie nicht sind, ist diese Frage nicht sehr sinnvoll.




Die Antworten Ihrer "Auch" -Fragen sind "Nein", "Nein" und "Nein". Nur weil eine Funktion rekursiv und / oder threadsicher ist, wird sie nicht einspringend.

Jeder dieser Funktionstypen kann bei allen angegebenen Punkten fehlschlagen. (Obwohl ich Punkt 5 nicht 100% sicher bin).




Jetzt muss ich auf meinen vorherigen Kommentar eingehen. @paercebal Antwort ist falsch. In dem Beispielcode hat niemand bemerkt, dass der Mutex, der als Parameter angenommen werden sollte, nicht wirklich übergeben wurde?

Ich bestreite die Schlussfolgerung, behaupte ich: Damit eine Funktion in Gegenwart von Nebenläufigkeit sicher ist, muss sie einspringend sein. Daher bedeutet gleichzeitig-sicher (normalerweise geschrieben thread-safe) Re-Entrant.

Weder thread safe noch reentrant haben etwas über Argumente zu sagen: wir sprechen von der gleichzeitigen Ausführung der Funktion, die immer noch unsicher sein kann, wenn unpassende Parameter verwendet werden.

Zum Beispiel ist memcpy () threadsicher und reentrant (normalerweise). Offensichtlich wird es nicht wie erwartet funktionieren, wenn es mit Zeigern auf die gleichen Ziele von zwei verschiedenen Threads aufgerufen wird. Das ist der Sinn der SGI-Definition, die auf dem Client liegt, um sicherzustellen, dass Zugriffe auf dieselbe Datenstruktur vom Client synchronisiert werden.

Es ist wichtig zu verstehen, dass es generell Unsinn ist , thread-safe Operation die Parameter einzuschließen. Wenn Sie irgendeine Datenbankprogrammierung gemacht haben, werden Sie verstehen. Das Konzept dessen, was "atomar" ist und durch einen Mutex oder eine andere Technik geschützt werden kann, ist notwendigerweise ein Benutzerkonzept: Die Verarbeitung einer Transaktion in einer Datenbank kann mehrere unterbrochene Modifikationen erfordern. Wer kann sagen, welche synchronisiert werden müssen, aber der Client-Programmierer?

Der Punkt ist, dass "Korruption" den Speicher auf Ihrem Computer nicht mit unserialisierten Schreibvorgängen verderben muss: Korruption kann immer noch auftreten, selbst wenn alle einzelnen Operationen serialisiert sind. Wenn Sie also fragen, ob eine Funktion Thread-sicher oder eingängig ist, bedeutet die Frage für alle angemessen getrennten Argumente: Die Verwendung gekoppelter Argumente ist kein Gegenbeispiel.

Es gibt viele Programmiersysteme da draußen: Ocaml ist eins, und ich denke auch Python, die viel nicht-reentranten Code in ihnen haben, aber die eine globale Sperre verwenden, um Thread-Zugriffe zu verschachteln. Diese Systeme sind nicht reentrant und sie sind nicht thread-sicher oder gleichzeitig-sicher, sie arbeiten sicher, einfach weil sie die Parallelität global verhindern.

Ein gutes Beispiel ist Malloc. Es ist nicht eingängig und nicht threadsicher. Dies liegt daran, dass auf eine globale Ressource (den Heap) zugegriffen werden muss. Die Verwendung von Schlössern macht es nicht sicher: Es ist definitiv nicht einspringend. Wenn die Schnittstelle zu malloc korrekt entworfen wurde, wäre es möglich, sie eingängig und threadsicher zu machen:

malloc(heap*, size_t);

Jetzt kann es sicher sein, da es die Verantwortung für die Serialisierung des gemeinsamen Zugriffs auf einen einzelnen Heap auf den Client überträgt. Insbesondere ist keine Arbeit erforderlich, wenn separate Heap-Objekte vorhanden sind. Wenn ein gemeinsamer Heap verwendet wird, muss der Client den Zugriff serialisieren. Die Verwendung einer Sperre innerhalb der Funktion ist nicht genug: Betrachten Sie einfach ein Malloc Sperren eines Heap * und dann ein Signal kommt und malloc auf dem gleichen Zeiger: Deadlock: Das Signal kann nicht fortfahren, und der Client kann auch nicht, weil es ist unterbrochen.

Im Allgemeinen machen Schlösser die Dinge nicht threadsicher. Sie zerstören die Sicherheit, indem sie unangemessen versuchen, eine Ressource zu verwalten, die dem Kunden gehört. Die Verriegelung muss vom Objekthersteller vorgenommen werden, das ist der einzige Code, der weiß, wie viele Objekte erstellt werden und wie sie verwendet werden.






Links