简体   繁体   English

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

[英]Prevent boost::asio::io_context stopping on empty poll call

This code calls the posted handle此代码调用发布的句柄

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

whereas this doesn't:而这不是:

    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活生生的例子

Is it by design?是设计使然吗? If is, why?如果是,为什么? Can I configure io_context somehow to change this behavior?我可以以某种方式配置io_context来改变这种行为吗?

io_service/io_context are designed to stop when they run out of work¹. io_service/io_context 旨在在它们用完工作时停止¹。

The docs for io_service and io_context contain: io_serviceio_context的文档包含:

Stopping the io_context from running out of work阻止 io_context 耗尽工作

Some applications may need to prevent an io_context object's run() call from returning when there is no more work to do.当没有更多工作要做时,某些应用程序可能需要阻止 io_context 对象的 run() 调用返回。 For example, the io_context may be being run in a background thread that is launched prior to the application's asynchronous operations.例如,io_context 可能正在后台线程中运行,该线程在应用程序的异步操作之前启动。 The run() call may be kept running by creating an object of type boost::asio::executor_work_guard<io_context::executor_type>: run() 调用可以通过创建 boost::asio::executor_work_guard<io_context::executor_type> 类型的 object 来保持运行:

 boost::asio::io_context io_context; boost::asio::executor_work_guard<boost::asio::io_context::executor_type> = boost::asio::make_work_guard(io_context); ...

To effect a shutdown, the application will then need to call the io_context object's stop() member function.为了实现关闭,应用程序需要调用 io_context 对象的 stop() 成员 function。 This will cause the io_context run() call to return as soon as possible, abandoning unfinished operations and without permitting ready handlers to be dispatched.这将导致 io_context run() 调用尽快返回,放弃未完成的操作并且不允许调度准备好的处理程序。

Alternatively, if the application requires that all operations and handlers be allowed to finish normally, the work object may be explicitly reset.或者,如果应用程序要求允许所有操作和处理程序正常完成,则可以显式重置工作 object。

 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.

Note that the "old-fashioned" Asio interface used a less generalized io_service::work object:请注意,“老式”的 Asio 接口使用了不太通用的io_service::work object:

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

This would then require you to do extra work for to be able to reset it:这将需要您做额外的工作才能重置它:

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

Restarting重启

Finally when the context did run out of work, you will have to restart() it before re-using it:最后,当上下文确实耗尽工作时,您必须在重新使用它之前重新restart()它:

在此处输入图像描述

Rationale基本原理

I think the rationale for the design comes from the library not having any opinions about how the service is run in terms of scheduling and threading, in combination with the guarantee that io_context / io_service must be thread-safe².我认为设计的基本原理来自图书馆对服务在调度和线程方面的运行方式没有任何意见,同时保证io_context / io_service必须是线程安全的²。 See docs for background .有关背景,请参阅文档


¹ Sidenote: Likewise, thread_pool (which is-a execution_context just like io_context is) is not designed for re-use (see eg Boost asio thread_pool join does not wait for tasks to be finished ) ¹旁注:同样, thread_pool (这是一个execution_context ,就像io_context一样)不是为重用而设计的(参见例如Boost asio thread_pool join does not wait for tasks to be completed )

² Except object lifetime (construction/destruction), of course ² 除了 object 寿命(构造/销毁),当然

This documented (not in best place, it should be mentioned in poll documentation):这已记录在案(不是最好的地方,应该在poll文档中提及):

io_context::restart - develop io_context::restart - 开发

io_context::restart io_context::重启

Restart the io_context in preparation for a subsequent run() invocation.重新启动io_context为后续的run()调用做准备。

void restart();无效重启();

This function must be called prior to any second or later set of invocations of the run() , run_one() , poll() or poll_one() functions when a previous invocation of these functions returned due to the io_context being stopped or running out of work.此 function 必须在run()run_one()poll()poll_one()函数的任何第二组或以后调用之前调用,当这些函数的先前调用由于io_context被停止或用完而返回时工作。 After a call to restart() , the io_context object's stopped() function will return false .调用restart()后, io_context对象的stopped() function 将返回false

This function must not be called while there are any unfinished calls to the run() , run_one() , poll() or poll_one() functions.当对run()run_one()poll()poll_one()函数有任何未完成的调用时,不得调用此 function。

So basically you need to add restart to make it work.所以基本上你需要添加restart才能让它工作。

https://wandbox.org/permlink/aXzz5GCAIMIvStnl https://wandbox.org/permlink/aXzz5GCAIMIvStnl

Here is an extra clue why.这是一个额外的线索为什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM