防止 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_service
和 io_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<>
)以上是关于防止 boost::asio::io_context 在空投票调用时停止的主要内容,如果未能解决你的问题,请参考以下文章