[boost::asio] Lebendauer von shared_ptr als Parameter bei Handlern



  • Moin,

    aus der Doku von boost::asio:

    The destruction sequence described above permits programs to simplify their resource management by using shared_ptr<>. Where an object's lifetime is tied to the lifetime of a connection (or some other sequence of asynchronous operations), a shared_ptr to the object would be bound into the handlers for all asynchronous operations associated with it. This works as follows:

    When a single connection ends, all associated asynchronous operations complete. The corresponding handler objects are destroyed, and all shared_ptr references to the objects are destroyed.
    To shut down the whole program, the io_service function stop() is called to terminate any run() calls as soon as possible. The io_service destructor defined above destroys all handlers, causing all shared_ptr references to all connection objects to be destroyed.

    Bedeutet das im Klartext, dass, wenn ich folgendes habe:

    void write(tcp::socket& socket, shared_ptr<buffer> buff) {
        async_write(socket, buffer(*buff), boost::bind(myhandler, buff, _1, _2));
    }
    

    ich davon ausgehen kann, dass buff mindestens bis zum Ende von myhandler gültig bleibt? Ich mir den also nicht extra merken muss?

    Gruß, Panke



  • ich verstehe die frage nicht
    shared_ptr garantiert dir dass dein buffer nicht gelöscht wird, so lange es noch shared_ptr darauf gibt.
    dein handler bekommt nen shared_ptr auf nen buffer.
    also muss der buffer noch leben.

    was hat das jetzt mit boost.asio zu tun?



  • Hustbaer, das ist auch mein Gedankengang.

    Ich war / bin mir nur nicht sicher,
    was genau hinter bind / async_write passiert. Wenn buff der einzige shared_ptr auf meinen buffer ist, ist dann garantiert, dass der buffer bis zum Handler lebt? Ich vermute ja, weil boost::bind den zwischenspeichert, wollte da nur eine
    Bestätigung haben.



  • Hey hustbaer,

    hustbaer schrieb:

    dein handler bekommt nen shared_ptr auf nen buffer.
    also muss der buffer noch leben.

    Bekommt der handler wirklich einen shared_ptr?
    Er dereferenziert ihn, somit bekommt er den Wert des Buffers und keinen shared_ptr, welcher den eigentlichen ref-counter in sich trägt.

    Just a thought. Das ist nur eine Frage ohne Fragezeichen.

    @Panke, schau in deinen anderen Thread, hab die Frage komischerweise dort beantwortet.



  • AmITrolling? schrieb:

    ...

    Argss... OK hab da was vermischt.
    Die Frage bleibt aber fast gleich:
    Das ist doch nicht sicher, wenn man den shared_ptr dereferenziert an async_write übergibt, oder irre ich mich da einfach nur?

    Der shared_ptr könnte doch währenddessen auf 0 gehen, BEVOR der completion_handler aufgerufen wird.



  • boost::bind und damit der Handler bekommt den shared_ptr, async_write den buffer dahinter.



  • Panke schrieb:

    boost::bind und damit der Handler bekommt den shared_ptr, async_write den buffer dahinter.

    Ja, ähh... nochmal bitte. Verstehe den Satz nicht.

    Der handler wird ja nicht erstellt, das ist bloß eine Signatur einer Funktion.

    Imagine:
    1.Funktionsaufruf von:

    async_write(socket, buffer(*buff), boost::bind(myhandler, buff, _1, _2)
    

    2. Der reference-counter von buff fällt währenddessen auf 0.
    3. 'myhandler' wird aufgerufen, will vom buffer lesen -> geht nicht weil der buffer in Schritt 2. gelöscht wurde.

    Ich sag nicht das es so ist! Das ist bloß eine Frage. Kann das passieren?
    Nochmal: Meiner Meinung nach darf man den shared_ptr nicht dereferenzieren, da er während des Lesens verloren gehen kann.



  • Nochmal: Meiner Meinung nach darf man den shared_ptr nicht dereferenzieren, da er während des Lesens verloren gehen kann.

    Dereferenzieren schon, nur beim verlassen des Scopes wird der Ref Count eins weniger und falls es die letze Ref war wird der buffer gelöscht!

    Edit:
    Eine Möglichkeit wäre, dein Handler so anzupassen, dass der Buffer (shared ptr) auch übergeben wird. So kannst Du den Buffer (shared ptr) beim bind übergeben und der Ref Count wird eins hochgezählt und der Buffer so am Leben erhalten.



  • Panke schrieb:

    Hustbaer, das ist auch mein Gedankengang.

    Ich war / bin mir nur nicht sicher,
    was genau hinter bind / async_write passiert.

    bind() erstellt einen Funktor, in den der shared_ptr als Parameter reingebunden wird. Heisst auf Deutsch: da steckt eine Kopie des shared_ptr drin.
    async_write() wiederum kopiert sich diesen Funktor, und führt ihn aus, wenn die Operation abgeschlossen wurde. (Und zerstört ihn dann nach dem Ausführen)

    Der Handler lebt also garantierterweise bis die Operation abgeschlossen wurde. Da der Buffer durch die Kopie des shared_ptr im Handler am Leben erhalten wird, ist also auch sichergestellt dass der Buffer lange genug lebt.



  • AmITrolling? schrieb:

    Imagine:
    1.Funktionsaufruf von:

    async_write(socket, buffer(*buff), boost::bind(myhandler, buff, _1, _2)
    

    2. Der reference-counter von buff fällt währenddessen auf 0.
    3. 'myhandler' wird aufgerufen, will vom buffer lesen -> geht nicht weil der buffer in Schritt 2. gelöscht wurde.

    Ich sag nicht das es so ist! Das ist bloß eine Frage. Kann das passieren?

    Nein, kann nicht passieren.
    Weil eben im mit bind() erstellten Handler eine Kopie des shared_ptr gemacht wird. Dadurch kann der Reference-Count nicht auf 0 fallen, der Buffer kann nicht zu früh gelöscht werden.



  • Danke hustbaer für die Klarstellung!


Anmelden zum Antworten