我何时必须使用boost :: asio:strand

use*_*360 8 c++ multithreading boost boost-asio

阅读boost :: asio的文档,我还不清楚何时需要使用asio :: strand.假设我有一个使用io_service的线程,那么可以安全地在套接字上写入如下吗?

void Connection::write(boost::shared_ptr<string> msg)
{
    _io_service.post(boost::bind(&Connection::_do_write,this,msg));
}

void Connection::_do_write(boost::shared_ptr<string> msg)
{
    if(_write_in_progress)
    {
      _msg_queue.push_back(msg);
    }
    else
    {
      _write_in_progress=true;
      boost::asio::async_write(_socket, boost::asio::buffer(*(msg.get())),
      boost::bind(&Connection::_handle_write,this,
             boost::asio::placeholders::error));
    }
}

void Connection::_handle_write(boost::system::error_code const &error)
{
  if(!error)
  {
    if(!_msg_queue.empty())
    {
          boost::shared_ptr<string> msg=_msg_queue.front();
      _msg_queue.pop_front();
      boost::asio::async_write(_socket, boost::asio::buffer(*(msg.get())),
           boost::bind(&Connection::_handle_write,this,
                   boost::asio::placeholders::error));
        }
    else
    {
      _write_in_progress=false;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

多个线程调用Connection :: write(..)或者我必须使用asio :: strand吗?

Arn*_*rtz 18

简短回答:不,你不必strand在这种情况下使用.

大致简化,io_service包含一个函数对象列表(处理程序).post()在服务上调用时,处理程序将被放入列表中.例如,每当异步操作完成时,处理程序及其参数就会被放入列表中. io_service::run()执行一个接一个的处理程序 因此,如果run()在您的情况下只有一个线程调用,则没有同步问题,也不strand需要s.
只有当多个线程同时调用run()io_service,才会同时执行多个处理程序,在N个线程中最多可以执行N个并发处理程序.如果这是一个问题,例如,如果队列中可能有两个处理程序同时访问同一个对象,则需要使用strand.
您可以将其strand视为一组处理程序的锁.如果一个线程执行一个与a关联的处理程序strand,它将strand被锁定,并在处理程序完成后释放它.任何其他线程只能执行与锁定无关的处理程序strand.

注意:这种解释可能过于简化,技术上也不准确,但它给出了sio_servicestrands中发生的事情的基本概念.


Tan*_*ury 5

仅从一个线程调用io_service::run()将导致所有事件处理程序在该线程内执行,无论有多少线程正在调用Connection::write(...)。因此,处理程序不可能并发执行,因此是安全的。该文档将其称为隐式链

另一方面,如果多个线程正在调用io_service::run(),则需要一个线程。 这个答案更详细地涵盖了股线。