提升::ASIO。确保仅在调用 async_receive(...) 后调用 io_service.run() ?
Posted
技术标签:
【中文标题】提升::ASIO。确保仅在调用 async_receive(...) 后调用 io_service.run() ?【英文标题】:BOOST::ASIO. Making sure io_service.run() is invoked only after async_receive(...) is called? 【发布时间】:2017-07-05 20:00:07 【问题描述】:我有一个问题,两个线程是这样调用的,一个接一个。
new boost::thread( &SERVER::start_receive, this);
new boost::thread( &SERVER::run_io_service, this);
第一个线程调用这个函数的地方。
void start_receive()
udp_socket.async_receive(....);
第二个线程调用,
void run_io_service()
io_service.run();
有时io_service
线程在start_receive()
线程之前完成,然后服务器无法接收数据包。
我曾考虑在两个线程之间放置一个睡眠函数,以等待一段时间以等待start_receive()
完成,这很有效,但我想知道是否有另一种可靠的方法来实现这一点?
【问题讨论】:
没有必要将 async_receive 放在自己的线程中。 asio 是异步的 好的,不知道,使用这个框架还是新手,但是异步函数只能在io_service
线程之前工作吗?换句话说,一个保证在另一个之前?
异步操作会导致 io_service::work 处于活动状态,直到调用完成处理程序。因此 io_service::run 调用在调用完成处理程序之前不会返回。
当io_service::run
在调用完成处理程序后返回时,它会停止阻塞并退出吗?对我来说,async_receive
似乎可以在程序期间继续接受数据包,而io_service::run
仅在启动时初始化?
查看我对前置/后置条件的回答。您需要阅读文档几次才能理解。我花了很长时间才明白这一切。
【参考方案1】:
当您调用io_service.run()
时,线程将阻塞,调度已发布的处理程序,直到:
没有与io_service
关联的io_service::work
对象,或者
io_service.stop()
被调用。
如果发生上述任何一种情况,io_service
将进入停止状态,并在未来拒绝调度任何处理程序,直到调用其 reset()
方法。
每次对与 io_service 关联的 io 对象启动异步操作时,都会在异步处理程序中嵌入一个 io_service::work 对象。
因此,在异步处理程序运行之前,上述第 (1) 点不会发生。
因此,此代码将保证异步过程完成并且断言通过:
asio::io_service ios; // ios is not in stopped state
assert(!ios.stopped());
auto obj = some_io_object(ios);
bool completed = false;
obj.async_something(..., [&](auto const& ec) completed = true; );
// nothing will happen yet. There is now 1 work object associated with ios
assert(!completed);
auto ran = ios.run();
assert(completed);
assert(ran == 1); // only 1 async op waiting for completion.
assert(ios.stopped()); // io_service is exhausted and no work remaining
ios.reset();
assert(!ios.stopped()); // io_service is ready to run again
【讨论】:
很好的解释,ASIO 开发者应该使用这个解释而不是这个。 boost.org/doc/libs/1_64_0/doc/html/boost_asio/reference/… 我一直觉得asio是一个杰作,但是文档让我们失望了。【参考方案2】:如果您想保持io_service
运行,请创建一个work
对象:
boost::asio::io_service svc;
auto work = std::make_shared<boost::asio::io_service::work>(svc);
svc.run(); // this will block as long as the work object is valid.
这种方法的好处是上面的work
对象将保持svc
对象“运行”,但不会阻止对其进行的任何其他操作。
【讨论】:
你的意思是我可以在async_recieve
调用之前或之后调用它?
不需要用指针来控制工作对象的生命周期。如果你想让 io 服务停止,只需调用 stop() 就可以了。
我已经有一个menu
线程允许io_service
停止和启动,但这是一个有趣的花絮,谢谢!以上是关于提升::ASIO。确保仅在调用 async_receive(...) 后调用 io_service.run() ?的主要内容,如果未能解决你的问题,请参考以下文章