阅读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;
}
}
}
多个线程调用Connection :: write(..)或者我必须使用asio :: strand?
答案 0 :(得分:18)
简短回答:不,在这种情况下,您不必使用strand
。
大致简化,io_service
包含一系列函数对象(处理程序)。在服务上调用post()
时,处理程序将被放入列表中。例如每当异步操作完成时,处理程序及其参数都将放入列表中。 io_service::run()
执行一个接一个的处理程序。因此,如果在您的情况下只有一个调用run()
的线程,则不存在同步问题,并且不需要strand
。
只有当多个线程在同一个run()
上调用io_service
时,才会同时执行多个处理程序,在N个线程中最多可以执行N个并发处理程序。如果这是一个问题,例如如果队列中可能有两个处理程序同时访问同一个对象,则需要strand
。
您可以将strand
视为一组处理程序的锁。如果线程执行与strand
关联的处理程序,则strand
被锁定,并在处理程序完成后释放。任何其他线程只能执行与锁定的strand
无关的处理程序。
警告: 此解释可能过于简化,技术上也不准确,但它提供了io_service
中所发生情况的基本概念。 strand
秒。
答案 1 :(得分:2)
只从一个线程调用io_service::run()
将导致所有事件处理程序在线程内执行,无论有多少线程正在调用Connection::write(...)
。因此,没有可能的并发执行处理程序,这是安全的。文档将其称为implicit strand。
另一方面,如果多个线程正在调用io_service::run()
,则需要一个链。 This回答更详细地介绍了这些内容。