C++ Boost::asio - Sinn hinter der ganzen Sache

Tockra

Lt. Commander
Dabei seit
Dez. 2008
Beiträge
1.042
Hey Leute,

Ich schaue mir aktuell aus Interesse die Boost Bibiliothek an und lese dafür diese Anleitung: http://www.highscore.de/cpp/boost/

Die ist eigentlich super, allerdings bin ich aktuell beim Kapitel 7 über Asynchrone Ein und Ausgaben angekommen.
Mit diesen kann ich mich noch nicht wirklich anfreunden.
Dort werden einige Beispiele genannt, aber eigentlich finde ich bei keinem den großen Vorteil an asio, deshalb wollte ich einfach mal fragen, ob mir das jmd. etwas genauer erklären kann.

Für mich ist eine Synchrone Funktion (Gegenteil von Assynchrone Funktion) ein ganz normaler Funktionsaufruf, sprich ich muss nach dem Aufruf warten, bis der Funktionsaufruf zurückkehrt.
Ein Assynchroner Aufruf ist für mich Aufruf, auf dessen Rückkehr man nicht warten muss. Das wäre für mich z.B.
Code:
void test() {
   //do something
}

int main() {
   thread t(test);
   //do something
   return 0;
}
Für mich ist ein Assynchroner Aufruf in Aufruf, der in einem anderen Thread ausgelagert wird und somit Assynchron und parrallel geschieht.

Das scheint Asio aber nicht zu machen, sondern die "ioservice.run()" Methode scheint alle zuvor gesammelten Assynchronen Aufrufe erst auszuführen, sprich alles was nach dem Assynchronen Aufruf und vor dem run geschieht kann den Assynchronen Aufruf verhindern (z.B. durch Blockieren).

Ich verstehe jetzt nicht so wirklich den großen Vorteil. Der AH Effekt tritt da bei mir nicht ein, weil ich anstelle der io_service.run() genau so gut die Assynchronen Aufrufe tätigen kann. Dazu kommt noch das run() auch blockiert, so dass man den Aufruf der Funktionen also einfach nur paar Zeilen tiefer geschoben hat...

Bitte erleuchtet mich ;)

Gruß
T
 

antred

Lt. Commander
Dabei seit
Juni 2010
Beiträge
1.288
Lies mal folgenden Abschnitt auf der von dir verlinkten Seite:

Es mag auf den ersten Blick verwundern, dass die asynchrone Datenverarbeitung den Aufruf einer Methode run() erfordert, die blockiert und das Programm anhält. Das ist aber insofern kein Problem als dass das Programm sowieso irgendwie davor bewahrt werden muss, beendet zu werden. Würde run() nicht blockieren, würde die Funktion main() zu Ende laufen und somit das gesamte Programm beendet werden. Für den Fall, dass man nicht auf die Rückkehr des Methodenaufrufes warten möchte und das Programm weiterlaufen soll, muss run() lediglich in einem neuen Thread aufgerufen werden. Denn run() hält selbstverständlich nicht das gesamte Programm an, sondern lediglich den aktuellen Thread.

Dass die Beispielprogramme dennoch irgendwann beendet werden, liegt daran, dass run() zurückkehrt, wenn der I/O Service, für den diese Methode aufgerufen wurde, nichts mehr zu tun hat. Für die obigen Programme bedeutet dies, dass sie dann beendet werden, wenn alle Wecker geklingelt haben. Denn dann gibt es keine asynchronen Operationen mehr, die auf ihren Abschluss warten.
Ich interpretiere das also so, daß man das in diesem trivialen Beispiel so getan hat, um zu verhindern, daß das Programm gleich beendet wird. In einem realen Programm würde man den Aufruf von run() in einen separaten Thread auslagern.
 
Zuletzt bearbeitet:

antred

Lt. Commander
Dabei seit
Juni 2010
Beiträge
1.288
Naja denoch sehe ich da keinen zweck, weil der Aufruf erst beim run geschieht und nicht schon zuvor, wenn der assynchrone call eigentlich gemacht wird.
Eine ähnliche Frage scheint auf Stackoverflow gestellt und beantwortet worden sein. http://stackoverflow.com/questions/1982595/boost-asio-io-service-run

FAZIT (so wie ich's verstanden habe):

1. Einen Handler registrieren, der sich nach jedem Aufruf wieder neu installiert, damit die io_service::run() nur dann abbricht, wenn du sie explizit stoppst.
2. io_service::run() in einem Sekundärthread aufrufen.
3. Aus anderen Threads heraus asynchrone I/O-Requests stellen.
4. Sekundärthread arbeitet asynchrone I/O-Requests so lange in io_service::run() ab, bis du via io_service::stop() Schicht im Schacht machst.

EDIT: Daß sich das alles irgend wie ziemlich kontraintuitiv anfühlt, finde ich allerdings auch. Ich hätte mir da eher so einen Ansatz wie der bei Intel Threading Building Block Library vorgestellt. Also man setzt einfach einen I/O-Request ab, und das Framework entscheidet dann für sich, ob es den mit Hilfe eines einzelnen Worker-Threads, eines ganzen Thread-Pools oder auch über andere Mechanismen (z.B overlapped I/O auf Windows) abarbeitet.
 
Zuletzt bearbeitet:
Top