2009-01-08 7 views
13

Ich habe in letzter Zeit viel mit Boost.Asio gespielt. Ich mag die Bibliothek sehr, da sie eine fantastische Möglichkeit bietet, die Leistung der heutigen Multicore-Systeme zu verbessern.Was ist die beste Methode, um die Lebensdauer eines Objekts bei Verwendung von Boost.Asio zu gewährleisten?

Eine Frage, die ich mir ein paar Mal gestellt habe, und ich dachte, es lohnt sich, die Objektrelation/Eigentumsrechte wegzuwerfen, wenn Async-Anrufe mit Asio gemacht werden.

Das Problem, das ich wiederholt habe, ist, dass Sie ziemlich oft ein Objekt "auslaufen lassen" müssen, das noch Async-Rückrufe ausstehen muss. Wenn dieses Objekt den Bereich verlässt, bevor der Rückruf aufgerufen wird, werden die Dinge unweigerlich zum Knall.

Um dies zu bekämpfen, habe ich die Vorlage boost::enable_shared_from_this als Basisklasse für die meisten asio-basierten Klassen verwendet. Dies funktioniert in Ordnung, aber es ist ein wenig beschwerlich: Normalerweise bedeutet dies auch, den Konstruktor zu schützen und der Klasse eine Factory-Methode hinzuzufügen, um sicherzustellen, dass alle Instanzen in einem shared_ptr erstellt werden.

Ich wollte nur wissen, wie andere Leute dieses Problem angegangen sind. Gehe ich das am besten? Oder habe ich meine Asio.Foo alle falsch?

Diskutieren ... :)

Antwort

1

Diese Art der Sache ist Asio beschränkt. Ich schrieb vor kurzem eine Thread-Pool-Klasse (mit Boost :: Thread), die fast das gleiche Problem hatte - die Threads würden die Thread-Pool-Klasse aufrufen, die sie erstellt hat, um zu sehen, welche Aufgabe sie als nächstes mit einem einfachen Zeiger erledigen mussten dazu, und wenn die Thread-Pool-Klasse mit einem noch laufenden Kind-Thread zerstört würde, würde das Programm abstürzen. Ich behandelte es, indem ich interrupt für jeden der Threads in dem Threadpooldestruktor aufruft und dann darauf wartete, dass alle beendet wurden, bevor der Destruktor zurückkehren konnte.

Wenn ich Ihre Shared-Pointer-Lösung verstehe, scheint sie die gleiche allgemeine Sache zu tun - sicherzustellen, dass das Element nicht zerstört werden kann, bis es nicht mehr benötigt wird. Eine ästhetisch ansprechende Lösung. Ich sehe keine bessere Antwort auf diese Art von Problem.

+0

Interessant erwähnen Sie dieses Szenario: mein Kollege (bekannt hier als Alan) tat das gleiche wie Sie und ich erwähnte die "Lösung", die ich gefunden hatte, denn für mich war es das gleiche Problem. Ich bin immer noch nicht glücklich mit ihm: Ich mag den Mangel an Determinismus nicht, aber dann, das ist Threading für Sie – jkp

2

Mit boost::enable_shared_from_this ist so ziemlich die Art und Weise, es zu tun. Sehen Sie sich außerdem an, wenn Sie Verweise auf das Objekt benötigen, das das Objekt nicht beibehalten soll, wenn es sich um die einzigen verbleibenden Verweise handelt.

Ein gutes Beispiel für die Verwendung weak_ptr: Ich verwende enable_shared_from_this in meiner Socket-Klasse, die boost::asio verwendet. Das boost::asio Framework ist das einzige, das persistente Verweise auf das Objekt über Lese- und Schreibhandler speichert. Wenn der Destruktor des Sockets aufgerufen wird, weiß ich also, dass der Socket geschlossen ist und ich in einem Handler "Dinge erledigen" kann, um für diesen geschlossenen Socket aufzuräumen. Die Anwendung, die nur den Socket verwendet, hat einen weak_ptr Verweis darauf, den sie zu einem shared_ptr fördert, wenn sie mit dem Socket arbeiten will (normalerweise um darauf zu schreiben). Diese Heraufstufung kann auf einen Fehler hin überprüft werden, falls der Socket wegging, obwohl der Close-Handler des Sockets normalerweise alle weak_ptr Referenzen aufräumt, bevor dies überhaupt geschieht.

Verwandte Themen