0

クライアントから送信されたリクエストを処理する、 boost asio ドキュメント(シングルスレッド サーバー)の HTTP サーバーの例から大きく影響を受けた、単純な非同期サーバーがあります。

serverのクラスは、connection新しいクライアントが接続してそのメソッドを呼び出すたびに新しいオブジェクトを作成しstart()ます (HTTP サーバーの例のように)。インスタンスはクライアントのリクエストを読み取り、その後非同期操作 (つまりと)connectionを使用して応答を送信します。boost::asio::async_readboost::asio::async_write

connectionクラスの簡略化されたバージョンは次のとおりです。

void connection::start() {
    // Read request from a client
    boost::asio::mutable_buffers_1 read_buffer = boost::asio::buffer(
            buffer_data_, REQUET_SIZE);
    boost::asio::async_read(socket_, read_buffer,
            boost::bind(&connection::handle_read_request, shared_from_this(),
                    read_buffer, boost::asio::placeholders::error,
                    boost::asio::placeholders::bytes_transferred));
}

// Error handling omitted for the sake of brievty
void connection::handle_read_request(boost::asio::mutable_buffers_1& buffer,
    const boost::system::error_code& e, std::size_t bytes_transferred) {
      request req = parse_request(buffer);
      if(req.type_ = REQUEST_TYPE_1) {
          reply rep(...........);
          rep.prepare_buffer(buffer_data_.c_array());
          // Send the request using async_write
          boost::asio::async_write(socket_,
               boost::asio::buffer(buffer_data_, rep.required_buffer_size()),
               boost::bind(&connection::stop, shared_from_this()));
      } else if(req.type_ = REQUEST_TYPE_2 {
          // Need to do heavy computational task
      }
}

これらはすべて非常にうまく機能しますが、場合によっては、重い計算タスクを実行する必要があります ( REQUEST_TYPE_2)。これらのタスクはhandle_read_request、シングルスレッド サーバーをブロックし、他のクライアントがサービスを開始できなくなるため、自分では実行できません。

理想的には、負荷の高い計算タスクをスレッド プールに送信し、connection::handle_done_task(std::string computation_result)タスクの完了時に接続クラスのメソッド (例: ) を実行したいと考えています。これhandle_done_task(std::string computation_result)により、計算の結果がクライアントに送信されます ( を使用boost::asio::async_write)。

どうすればそれができますか?注意すべき問題がいくつかありますか (boost::asio::async_write複数のスレッドから同じソケットで呼び出しても安全ですか)?

4

1 に答える 1

0

strandドキュメントに明示的に記載されているように、asio オブジェクト ( /を除く) はスレッドセーフではないため、同期せずに複数のスレッドからio_service呼び出すべきではありません。async_write代わりに、post-to-io_service イディオムを使用してください。このような:

// pseudocode, untested!
if (req.type_ = REQUEST_TYPE_2) 
{
  auto self = shared_from_this(); // lets capture shared_ptr<connection> to ensure its lifespan
  auto handler = [=](computation_result_type res)
  {
    // post the function that accesses asio i/o objects to `io_service` thread
    self->io_->post([] { handle_done_task(res); });
  }

  thread worker([=](const std::function<(computation_result_type res)> &handler) 
  {     
    // do the heavy work...
    // then invoke the handler
    handler(result);
  });
  worker.detach();
}
于 2013-10-05T18:31:46.543 に答える