Verfügbarkeit eines Objektes in einem anderen Thread



  • Schönen Morgen euch,

    ich bin derzeit dabei, mich wieder in C++ einzuarbeiten. Seit einigen Jahren entwickle ich in C#, nun möchte ich mich in C++ wieder einfinden, früher entwickelte ich auch in C++, dies ist aber schon ein bisschen her. Deshalb habe ich eine kleine Verständnisfrage.

    Nehmen wir an ich habe eine Methode Namens: "CreateNewThread".
    In dieser Methode erstelle ich ein neues Objekt, dieses nennt sich: "LifteTimeObject". Nun erstelle ich einen neuen Thread. Diesen Thread übergebe ich mittels Referenz mein erstelltes Objekt. Der erstelle Thread verrichtet irgendeine Aufgabe, welche länger dauert, als die Funktion CreateNewThread. Damit meine ich, dass diese Funktion ihr Ende erreicht hat. Alle in dieser erstellten Objekte werden gelöscht. Was geschieht jetzt mit dem Objekt LifteTimeObject? Da dieses ja nur eine Referenz auf das Objekt ist, welches sich in der Funktion CreateNewThread befindet, müsste dieses Objekt natürlich auch zerstört werden. Somit versucht der erstelle Thread jetzt auf ein Objekt zuzugreifen, bzw. auf eine Adresse, welche aber nicht mehr existiert. Ergo, es führt zu einem Fehler.
    Trifft meine Annahme zu?

    Um dies zu verhindern, muss ich selber Speicher mittels "new" reservieren und dieses natürlich auch wieder freigeben, damit sollte das Problem beseitig werden, oder? Zusätzlich würde ich statt "new" einen Smart-Pointer nutzen, ist dies besser? Wenn ja, warum?

    Hoffe das mir da jemand mal was genaueres Erklären kann.

    Grüße Marcel



  • Hallo,

    ja, deine Annahme ist richtig.

    Warum wird LifteTimeObject nicht kopiert?
    Zu gross (deiner Meinung nach) oder wird es sowohl vom Thread als auch von CreateNewThread 'gleichzeitig' benötigt?



  • Jockelx schrieb:

    Hallo,

    ja, deine Annahme ist richtig.

    Warum wird LifteTimeObject nicht kopiert?
    Zu gross (deiner Meinung nach) oder wird es sowohl vom Thread als auch von CreateNewThread 'gleichzeitig' benötigt?

    Naja, das finde ich noch heraus zu finden.
    Eigentlich ist das wieder eine andere Frage.
    Habe mich ein bisschen eingelesen, wann ich welche "Übergabeart" nutze sollte und bin zu diesem Entschluss gekommen (Priorität absteigen):

    • Const Reference: Möglichst immer dann nutzen, wenn man das Objekt nicht modifizieren möchte
    • Refernece: Möglichst immer dann benutzen, wenn du das Objekt modifizieren möchtest
    • Value Passing: Möglichst selten benutzen, da teilweiße ressourcenaufwendig. Nur wenn du wirklich eine Kopie des Objektes benötigst.

    Ich denke eher, dass ich mit meinem Entschluss ziemlich daneben liege, jedoch habe ich das so auf die schnelle im WWW zusammen gefunden.

    Grüße Marcel



  • Die ersten beiden fallen aber eben weg, da das Original gelöscht wird und die Referenz somit auf Garbage zeigt. Also bleibt dir nurnoch
    A: per value, Object wird kopiert
    B: per rvalue/move, Object wird verschoben
    C: Konstruktor-Parameter übergeben, der Thread erstellt das Object dann selbst
    😨 Pointer



  • tkausl schrieb:

    Die ersten beiden fallen aber eben weg, da das Original gelöscht wird und die Referenz somit auf Garbage zeigt. Also bleibt dir nurnoch
    A: per value, Object wird kopiert
    B: per rvalue/move, Object wird verschoben
    C: Konstruktor-Parameter übergeben, der Thread erstellt das Object dann selbst
    😨 Pointer

    Danke, stimmt rvalue hatte ich noch nicht auf meinem Radar. sollte ich mir mal anschauen. Schön, dann habe ich den ersten Teil verstanden.
    Vergessen wir mal kurz das obige Beispiel, kann man die Liste, welche ich oben verfast habe, so anwenden (Wenn natürlich alles im Scope ist)?
    Oder gibt es da andere "Regeln"?

    Grüße Marcel



  • Die Regeln sind gut, gelten aber nur für 'grössere' Objekte.
    Ein const long& ist z.B nicht schön. Ein const Point& ist egal, aus konsistens Gründen würde ich aber const& nehmen.

    Ergänzend: Pointer für optionale-Werte und zum nachgooglen (wenn du lust hast, ist interessant, aber nicht so wichtig) 'sink-parameter'.



  • Als Ergänzung: Bisher hat man es soweit möglich vermieden, Objekte zu kopieren, weil das immer schneller war. Das relativiert sich aber mit zunehmender Parallelität: Kopien vermeiden Abhängigkeiten die oft schwer zu behandeln sind und das Programm ausbremsen können, selbst wenn es nicht so offensichtlich ist. Auch vereinfacht dies, die Lebensdauer von Objekten zu managen.



  • TNA schrieb:

    Als Ergänzung: Bisher hat man es soweit möglich vermieden, Objekte zu kopieren, weil das immer schneller war. Das relativiert sich aber mit zunehmender Parallelität: Kopien vermeiden Abhängigkeiten die oft schwer zu behandeln sind und das Programm ausbremsen können, selbst wenn es nicht so offensichtlich ist. Auch vereinfacht dies, die Lebensdauer von Objekten zu managen.

    Als Anekdote zur Ergänzung:

    Ich arbeite gerade an einem Projekt in dem ein Thread eine sortierte Liste mit einer Handvoll Elementen modifiziert (einfügen und entfernen), welche von mehreren anderen Threads gelesen wird. Da diese anderen Threads Video-Frames rendern, kann ich mir eigentlich nicht erlauben, den Zugriff auf diese Liste mit einem Mutex zu synchronisieren - wenn ein Thread auf die Freigabe des Locks warten muss, kann das nämlich duchaus so lange dauern, dass dieser ein VSync verpasst, was sich durch vereinzelte "Mikro-Ruckler" bemerkbar macht.
    Stattdessen erstelle ich bei jeder Modifikation der Liste eine neue Kopie und weise diese einem std::shared_ptr zu. Auf diese Weise kann sich jeder Thread für das Rendering einen std::shared_ptr auf die Liste holen (Shared Pointer-Zuweisungen sind threadsicher und im Allgemeinen über atomare Operationen implementiert), bei dem garantiert ist, dass diese Liste sich nicht mehr verändert. So kann ich mir das Lock komplett sparen, und vermeide dass ein Thread an dieser Stelle zu lange auf einen gesperrten Mutex warten muss.
    Die Verwaltung der Liste wird zwar teurer, aber dafür auf ein Mutex-Lock verzichten zu können kann sich je nach Anwendungsfall lohnen.

    Gruss,
    Finnegan


Anmelden zum Antworten