防止 boost::asio::io_context 在空投票调用时停止

Posted

技术标签:

【中文标题】防止 boost::asio::io_context 在空投票调用时停止【英文标题】:Prevent boost::asio::io_context stopping on empty poll call 【发布时间】:2020-08-12 13:52:21 【问题描述】:

此代码调用发布的句柄

    boost::asio::io_context ioc;
    boost::asio::post(ioc, [] std::cout << "lol" << std::endl; );
    ioc.poll();

而这不是:

    boost::asio::io_context ioc;
    ioc.poll(); // empty, set internal state to stopped_
    boost::asio::post(ioc, [] std::cout << "lol" << std::endl; );
    ioc.poll(); // doesn't work as stopped() now returns true

Live example

这是设计使然吗?如果是,为什么?我可以以某种方式配置io_context 来改变这种行为吗?

【问题讨论】:

【参考方案1】:

io_service/io_context 设计为在它们用完工作时停止¹。

io_serviceio_context 的文档包含:

阻止 io_context 耗尽工作

当没有更多工作要做时,某些应用程序可能需要阻止 io_context 对象的 run() 调用返回。例如,io_context 可能在应用程序异步操作之前启动的后台线程中运行。 run() 调用可以通过创建 boost::asio::executor_work_guard<:executor_type>:

类型的对象来保持运行
boost::asio::io_context io_context;
boost::asio::executor_work_guard<boost::asio::io_context::executor_type>
  = boost::asio::make_work_guard(io_context);
...

为了实现关闭,应用程序需要调用 io_context 对象的 stop() 成员函数。这将导致 io_context run() 调用尽快返回,放弃未完成的操作并且不允许调度准备好的处理程序。

或者,如果应用程序要求允许所有操作和处理程序正常完成,则可以显式重置工作对象。

boost::asio::io_context io_context;
boost::asio::executor_work_guard<boost::asio::io_context::executor_type>
  = boost::asio::make_work_guard(io_context);
...
work.reset(); // Allow run() to exit.

请注意,“老式”的 Asio 接口使用了不太通用的 io_service::work 对象:

io_service ios;
io_service::work work(ios); // old interface!

这需要你做额外的工作才能重置它:

asio::io_service ios;
std::optional<asio::io_service::work> work(ios);
// ...
work.reset();

重启

最后,当上下文确实用完时,你必须restart()它才能重新使用它:

基本原理

我认为设计的基本原理来自图书馆没有任何 关于服务如何在调度和线程方面运行的意见,在 结合保证io_context/io_service必须是 线程安全²。见docs for background。


¹ 旁注:同样,thread_pool(即 execution_context 就像 io_context 一样)不是为重复使用而设计的(参见例如 Boost asio thread_pool join does not wait for tasks to be finished)

² 当然,对象生命周期(构造/销毁)除外

【讨论】:

顺便说一下,在新的执行器模型中,可以通过将on_work_started / on_work_finished operations 实现为无操作来实现不依赖工作的执行器。但这有点进入扩展/实现领域。【参考方案2】:

这个文档(不是最好的,应该在poll文档中提到):

io_context::restart - develop

io_context::restart

重新启动io_context,为后续的run() 调用做准备。

无效重启();

此函数必须在 run()run_one()poll()poll_one() 函数的任何第二组或更晚的调用之前调用,当这些函数的先前调用由于 io_context 被返回时停止或没有工作。调用restart() 后,io_context 对象的stopped() 函数将返回false

当对 run()run_one()poll()poll_one() 函数有任何未完成的调用时,不得调用此函数。

所以基本上你需要添加restart 才能使其工作。

https://wandbox.org/permlink/aXzz5GCAIMIvStnl

这是an extra clue为什么。

【讨论】:

值得补充:restart 函数不会删除等待就绪的处理程序。不过,我不知道为什么界面是这样设计的。这不是我所期望的。 只需使用工作警卫(asio::io_service ::work,或更现代的make_executor_work_guard 助手) @sehe 这正是我想要的。从未在文档中看到过这一点。你会发布答案吗? @jaskmar done (我也记错了make_work_guard 的名字——这个班级确实是exucutor_work_guard&lt;&gt;

以上是关于防止 boost::asio::io_context 在空投票调用时停止的主要内容,如果未能解决你的问题,请参考以下文章

PHP 怎么防止GET方式提交重复数据?

如何防止网站被*** 防止网站数据被***篡改

MyBatis怎么防止SQL注入

如何彻底防止SQL注入?

怎么防止网站被***和防止服务器被黑

在winform当中提交数据,如何防止重复提交?