boost::asio::strand::dispatch(handle) 还是直接调用handle?
boost::asio::strand::dispatch(handle) or call the handle directly?
我是 boost::asio 的新手。提升 doc 说:
The strand object guarantees that handlers posted or dispatched through the strand will not be executed concurrently. The handler may be executed inside this function if the guarantee can be met. If this function is called from within a handler that was posted or dispatched through the same strand, then the new handler will be executed immediately.
所以我想知道什么时候会立即执行新的处理程序,为什么不直接调用它而不是使用 dispatch?
如果调用者总是 运行 在链中,那么可以直接调用处理程序。否则,如果调用者并不总是 运行 在链中,那么可以使用 strand.dispatch()
来满足并发要求,同时可能优化一些调用链。
例如,考虑这样一种情况,其中应用程序协议要求定期发送心跳并响应每个心跳请求。可以设计异步调用链,以便有两个离散的调用链:
a keepalive
class负责一个周期性发送心跳的调用链。它将设置一个计时器到期,并在到期时设置一个新的到期时间并发送心跳:
.---------------------------.
V |
keepalive::start_timer() |
{ |
timer_.expires_from_now(...); |
timer_.async_wait( |
[this](...) |
{ |
this->start_timer(); -----'
io.send_headerbeat();
});
}
keepalive.start_timer();
an io
class 管理套接字,使用私有链来序列化对套接字的访问。 io
class 将从套接字读取并处理读取的数据。
.-------------------------------------.
V |
io::read_data() |
{ |
async_read(socket_, buffer_, |
strand_.wrap([this](...) |
{ |
auto message = parse(buffer_); |
this->read_data(); ----------------'
if (is_heartbeat_request(message))
{
this->send_heartbeat();
}
}));
}
io::start()
{
strand_.post([this]{ this->read_data(); });
}
在keepalive
的调用链中,io::send_heartbeat()
是从io
的私有链外部调用的,keepalive
无法访问。另一方面,在io
的调用链中,io::send_heartbeat()
是从链内部调用的。如果 io::send_heartbeat()
分派一个将在套接字上启动写入操作的处理程序,那么它将与两个异步调用链一起正常且透明地工作。此外,当在 io
调用链中调用时,处理程序会立即执行,从而避免了发布和与链同步的开销。
io::send_heartbeat()
{
strand_.dispatch(
[this]()
{
async_write(this->socket_, ...,
this->strand_.wrap(...));
});
}
strand::dispatch()
将立即在当前线程中执行处理程序,如果:
strand::running_in_this_thread()
returns true
strand::running_in_this_thread()
returns false
并且调用者正在 运行 宁 io_service
并且可以满足 strand 指定的处理程序调用顺序
没有 public API 来确定第二种情况的所有条件。因此,无法确定直接调用处理程序是否安全,而必须改为使用 strand::dispatch()
.
我是 boost::asio 的新手。提升 doc 说:
The strand object guarantees that handlers posted or dispatched through the strand will not be executed concurrently. The handler may be executed inside this function if the guarantee can be met. If this function is called from within a handler that was posted or dispatched through the same strand, then the new handler will be executed immediately.
所以我想知道什么时候会立即执行新的处理程序,为什么不直接调用它而不是使用 dispatch?
如果调用者总是 运行 在链中,那么可以直接调用处理程序。否则,如果调用者并不总是 运行 在链中,那么可以使用 strand.dispatch()
来满足并发要求,同时可能优化一些调用链。
例如,考虑这样一种情况,其中应用程序协议要求定期发送心跳并响应每个心跳请求。可以设计异步调用链,以便有两个离散的调用链:
a
keepalive
class负责一个周期性发送心跳的调用链。它将设置一个计时器到期,并在到期时设置一个新的到期时间并发送心跳:.---------------------------. V | keepalive::start_timer() | { | timer_.expires_from_now(...); | timer_.async_wait( | [this](...) | { | this->start_timer(); -----' io.send_headerbeat(); }); } keepalive.start_timer();
an
io
class 管理套接字,使用私有链来序列化对套接字的访问。io
class 将从套接字读取并处理读取的数据。.-------------------------------------. V | io::read_data() | { | async_read(socket_, buffer_, | strand_.wrap([this](...) | { | auto message = parse(buffer_); | this->read_data(); ----------------' if (is_heartbeat_request(message)) { this->send_heartbeat(); } })); } io::start() { strand_.post([this]{ this->read_data(); }); }
在keepalive
的调用链中,io::send_heartbeat()
是从io
的私有链外部调用的,keepalive
无法访问。另一方面,在io
的调用链中,io::send_heartbeat()
是从链内部调用的。如果 io::send_heartbeat()
分派一个将在套接字上启动写入操作的处理程序,那么它将与两个异步调用链一起正常且透明地工作。此外,当在 io
调用链中调用时,处理程序会立即执行,从而避免了发布和与链同步的开销。
io::send_heartbeat()
{
strand_.dispatch(
[this]()
{
async_write(this->socket_, ...,
this->strand_.wrap(...));
});
}
strand::dispatch()
将立即在当前线程中执行处理程序,如果:
strand::running_in_this_thread()
returnstrue
strand::running_in_this_thread()
returnsfalse
并且调用者正在 运行 宁io_service
并且可以满足 strand 指定的处理程序调用顺序
没有 public API 来确定第二种情况的所有条件。因此,无法确定直接调用处理程序是否安全,而必须改为使用 strand::dispatch()
.