[boost.asio] HTTP Server 3 Beispiel und Sinn von Strands...



  • Hallo,

    Mal eine Frage an boost.asio-Kenner:
    Ich bis gerade etwas mit boost.asio am rumbasteln. Im Beispiel HTTP Server 3 wird mit einem Thread-Pool gearbeitet, in dem mehrere Male io_service::run gestartet wird. Man hat dann also mehrere Threads in denen Completion-Handler ausgeführt werden können. Soweit so gut.

    Nun gibt es ja noch io_service::strand-Objekte, mit denen man potentiell parallel ablaufende Completion-Handler serialisieren kann. Im oben genannten Beispiel wird das für receive- und write-Handler einer HTTP-Verbindung gemacht.

    Mir stellt sich allerdings die Frage: wozu? Ein Completion-Handler wird doch eh erst ausgeführt, wenn die damit Verbundene asynchrone Operation abgeschlossen ist, oder? Die Aufrufreihenfolge sollte also doch per se sequentiell sein.

    Hier mal der betreffende Auschnitt aus dem Beispielcode:

    Boost.Asio Doku schrieb:

    oid connection::start()
    {
      //wozu hier der strand? Der Completion Handler (also das handle_read weiter unten) wird doch erst aufgerufen, wenn async_read_some abgeschlossen wird, oder?
      socket_.async_read_some(boost::asio::buffer(buffer_),
          strand_.wrap(
            boost::bind(&connection::handle_read, shared_from_this(),
              boost::asio::placeholders::error,
              boost::asio::placeholders::bytes_transferred)));
    }
    
    void connection::handle_read(const boost::system::error_code& e,
        std::size_t bytes_transferred)
    {
      if (!e)
      {
        boost::tribool result;
        boost::tie(result, boost::tuples::ignore) = request_parser_.parse(
            request_, buffer_.data(), buffer_.data() + bytes_transferred);
    
        if (result)
        {
          request_handler_.handle_request(request_, reply_);
          //siehe oben
          boost::asio::async_write(socket_, reply_.to_buffers(),
              strand_.wrap(
                boost::bind(&connection::handle_write, shared_from_this(),
                  boost::asio::placeholders::error)));
        }
        else if (!result)
        {
          reply_ = reply::stock_reply(reply::bad_request);
          //siehe oben
          boost::asio::async_write(socket_, reply_.to_buffers(),
              strand_.wrap(
                boost::bind(&connection::handle_write, shared_from_this(),
                  boost::asio::placeholders::error)));
        }
        else
        {
          //siehe oben
          socket_.async_read_some(boost::asio::buffer(buffer_),
              strand_.wrap(
                boost::bind(&connection::handle_read, shared_from_this(),
                  boost::asio::placeholders::error,
                  boost::asio::placeholders::bytes_transferred)));
        }
      }
    


  • Ganze 8 Monate später...
    Habe beim rumgooglen deine Frage gefunden, vor die ich mich auch konfrontiert sah...

    Das sehe ich ganz genau so. Die Reihefolge ist hier eh sequentiell.

    So wie ich das sehe ist das srand Objekt nur der Besitzer des connection Objekts (einziger der noch einen shared_ptr auf connection besitzt). Dies hatte im Beispiel Http Server die Klasse connection_container erledigt.

    Wird der letzte Completion-Handler verlassen, terminiert srand und damit der letzte shared_ptr auf connection und somit connection selbst...
    (siehe quellcode-kommentare am ende von connection::handle_read und connection::handle_write)

    Grüße.


Anmelden zum Antworten