Boost Asio服务器问题。使用线程池时随机阻塞受体套接字

时间:2019-04-16 21:56:32

标签: multithreading boost server asio

我在这里看到过类似问题的文章,但是我的问题有所不同,没有答案可以帮助我解决这个问题。我有一个基于此boost http/server3示例的多线程boost asio异步HTTP服务器。我正在使用boost 1.64.0,并且正在Windows 10 64位上对其进行测试。在VS 2015 64上编译

我有一个线程池,该线程池调用  io_service.run()。服务器的基本思想是我有一个线程池,所有线程都在侦听传入的请求。当我使用单线程时,一切正常。网页加载没有问题。但是问题出在我使用2个以上线程时。 如果一个线程尚未完成其工作(例如,忙于某个正在处理数据库的POST请求),接收器套接字(随机)将不接受某些请求,并等待直到第一个线程完成(请求显示为在Firefox中的“网络”标签中待处理)。有时页面加载没有问题,但大多数情况下页面会停顿直到第一个线程完成工作为止。有谁知道可能导致此问题的原因?

我尝试使用BOOST_ASIO_ENABLE_HANDLER_TRACKING定义来跟踪问题,直到问题停顿为止

@asio|1555450197.805179|3404*3407|strand@0000024EAAB649E0.dispatch
@asio|1555450197.805179|>3407|
@asio|1555450197.805179|3407*3408|socket@0000024EAAD400A0.async_send
@asio|1555450197.806177|<3407|
@asio|1555450197.806177|<3404|
@asio|1555450197.806177|>3405|ec=system:0
@asio|1555450197.806177|3405*3409|socket@0000024EAAB76D20.async_receive
accepting request
@asio|1555450197.806177|3405*3410|socket@0000024EA92D9CF0.async_accept
@asio|1555450197.806177|<3405|
@asio|1555450197.806177|>3408|ec=system:0,bytes_transferred=24530
@asio|1555450197.806177|3408*3411|strand@0000024EAAB649E0.dispatch
@asio|1555450197.806177|>3411|
@asio|1555450197.806177|<3411|
@asio|1555450197.806177|0|socket@0000024EAAD400A0.close
@asio|1555450197.806177|<3408|
@asio|1555450197.806177|>3409|ec=system:0,bytes_transferred=375
@asio|1555450197.807174|3409*3412|strand@0000024EAAB64580.dispatch
@asio|1555450197.807174|>3412|
@asio|1555450197.807174|3412*3413|socket@0000024EAAB76D20.async_send
@asio|1555450197.807174|<3412|
@asio|1555450197.807174|<3409|
@asio|1555450197.807174|>3413|ec=system:0,bytes_transferred=26952
@asio|1555450197.807174|3413*3414|strand@0000024EAAB64580.dispatch
@asio|1555450197.807174|>3414|
@asio|1555450197.807174|<3414|
@asio|1555450197.807174|0|socket@0000024EAAB76D20.close
@asio|1555450197.808173|<3413|

这是我的构造函数

      boost::asio::ip::tcp::resolver resolver(io_service_); 
      boost::asio::ip::tcp::resolver::query query(address, port);
      boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query); 



      acceptor_.open(endpoint.protocol()); 
      acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
      acceptor_.bind(endpoint); 

      acceptor_.listen(); 

      boost::system::error_code error;
      handle_accept(error);

我的句柄接受功能

void server::handle_accept(const boost::system::error_code& e)
{
    if (!e)
    {

        new_connection_.reset(new connection(io_service_, *request_handler_, max_cont_lenght, min_upload_speed));

        acceptor_.async_accept(new_connection_->socket(), [this](boost::system::error_code error)
        {
            this->start_accept(error);

        });


    }
}

启动接受功能

void server::start_accept(const boost::system::error_code& e)
{
    if (!e)
    {
        new_connection_->start();
    }

    handle_accept(e);
} 

服务器运行功能

void server::run()
{
  // Create a pool of threads to run all of the io_services.
  for (std::size_t i = 0; i < thread_pool_size_; ++i)
  {

      std::shared_ptr<boost::thread> thread(new boost::thread(
         [this](){
          this->io_service_run();
      }
      ));

    threads.push_back(thread);
  }

  // Wait for all threads in the pool to exit.
  for (std::size_t i = 0; i < threads.size(); ++i)
  {
    threads[i]->join();
  }
}

1 个答案:

答案 0 :(得分:0)

通过简单的暴力破解,我弄清了这个问题的原因。显然,这不是接受者的问题,问题出在连接类中。在同一 http/server3示例中。仅当您将回调函数包装成一束时,这种情况才会发生。

  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)));

有趣的是,handle_read函数中使用的同一链似乎没有引起此问题。根据文档,http / server3实现是正确的

  

显式链是io_service :: strand的实例。所有事件处理程序功能对象都需要使用io_service :: strand :: wrap()进行包装,或者通过io_service :: strand对象进行发布/分发。   对于组合式异步操作(例如async_read()或async_read_until()),如果完成处理程序经过一个链,则所有中间处理程序也应经过同一链。为了确保线程安全地访问在调用方和组合操作之间共享的任何对象

但是从连接start()函数中删除strand_.wrap似乎可以解决此问题。不知道这是Boost 1.64中的错误还是我丢失了某些东西。