提升 asio 行为 - 从多个线程调用 ios_service::run
Posted
技术标签:
【中文标题】提升 asio 行为 - 从多个线程调用 ios_service::run【英文标题】:boost asio behaviour - calling ios_service::run from multiple threads 【发布时间】:2014-07-20 00:03:04 【问题描述】:我正在尝试使用 boost::asio 截止时间计时器来延迟函数调用,如下所示
#include <boost/asio.hpp>
#include "boost/thread.hpp"
#include <iostream>
class MyTest
public:
MyTest()
:_invokeCount(0),
_handleCount(0)
void handler(int i)
std::cout<<"\t\tHandled " <<i << std::endl;
++_handleCount;
void RunIOService()
std::cout<<"\tStarted :"<< _invokeCount<< std::endl;
_ios.run();
std::cout<<"\tFinished "<< _invokeCount << std::endl;
void invokeTimer()
std::cout<<"invoked " << ++_invokeCount << std::endl;
boost::asio::deadline_timer t(_ios, boost::posix_time::milliseconds(5));
t.async_wait(boost::bind(&MyTest::handler, this, _invokeCount));
boost::thread th = boost::thread(boost::bind(&MyTest::RunIOService, this));
void PrintCount()
std::cout<<"Count = "<< _invokeCount << std::endl;
void Wait()
while (_invokeCount > _handleCount)
std::cout<<"X ";
Sleep(1000);
private:
int _invokeCount;
int _handleCount;
boost::asio::io_service _ios;
;
int main(int argc, char* argv[])
MyTest test;
for (int k=0; k<5; ++k)
test.invokeTimer();
Sleep(40);
test.Wait();
test.PrintCount();
return EXIT_SUCCESS;
这个应用程序的输出不是我预期的:-
invoked 1
Started :1
Handled 1
Finished 1
invoked 2
Started :2
Finished 2
invoked 3
Started :3
Handled 2
Finished 3
invoked 4
Started :4
Handled 3
Finished 4
invoked 5
Started :5
Handled 4
Finished 5
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
我希望在 ios_service::run 返回之前调用每个处理程序,但从输出中看起来并非如此(在 Started:2 和 Finished:2 之间缺少输出)。此外,应用程序永远不会退出。即第 5 个处理程序永远不会被调用。
我错过了什么?
谢谢!
【问题讨论】:
【参考方案1】:有几点:
-
您可能不需要 5 个线程。为什么不创建一个线程并将事件触发到线程中运行的单个 ioservice 实例中
尝试在线程运行函数中使用
io_service::work
,以在处理所有请求时将io_service
保持在范围内。
等待结束后,停止io_service
,加入线程并退出程序
在这里阅读io_service::work
: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/io_service.html
【讨论】:
谢谢 - 在实际应用程序中,等效于 invokeTimer 的函数是基于事件的,所以我的想法是在事件到达时启动一个短期线程,而不是在整个生命周期内运行一个单独的线程应用程序(不确定 ios_service::work 的负载)。 Sammy - 你可以相信work
是高效的:它正是为此目的而设计的。线程池中的休眠线程没有运行时开销。 io_service
实际上是一个线程安全的任务队列,后台线程只是在等待工作到达时休眠。 (我会说使用带有“每个事件线程”模型的 Boost Asio 是本末倒置)
(PS。重用相同队列/线程的开销(即使用io_service::work
时)绝对小于启动一个新线程。Eeek)【参考方案2】:
我在每个 ios_service::run() 之后添加了 ios_service::reset() 并且它按预期工作。
【讨论】:
【参考方案3】:boost::asio::ioservice::reset() 应该在后面的一组 run() 调用之前调用。 正如boost doc所说: 当由于 io_service 停止或用完而返回这些函数的先前调用时,必须在任何第二组或以后调用 run()、run_one()、poll() 或 poll_one() 函数之前调用此函数工作。此函数允许 io_service 重置任何内部状态,例如“停止”标志。
当对 run()、run_one()、poll() 或 poll_one() 函数有任何未完成的调用时,不得调用此函数。
【讨论】:
以上是关于提升 asio 行为 - 从多个线程调用 ios_service::run的主要内容,如果未能解决你的问题,请参考以下文章