boost :: asio :: io_service如何优先工作?

时间:2012-05-10 09:04:39

标签: c++ sockets boost boost-asio

我使用boost::asio::io_service来管理一些异步TCP通信。这意味着我创建了boost::asio::ip::tcp::socket并将io_service提供给它。当我开始沟通时,它会像这样示意:

Async Resolve -> Callback -> Async Connect -> Callback -> Async Write -> Callback -> Async Read

我省略了像resolve和bind这样的部分。假设Socket已绑定到端口并且主机名已解析(因此连接意味着建立与端点的真实连接)

现在重点是我可以使用相同的io_service对象启动多个异步连接。这意味着,例如,在我的io_service线程中,程序即将Async Write一些数据,主线程将在Socket上调用Async Resolve(但具有相同的io_service })。 这意味着我的io_service现在有一些平行的工作要做 - 我想知道它将如何确定工作的优先顺序?

例如它就像这样

Main Thread              |      io_service Thread
-------------------------+-----------------------------------------------
SocketA->Async Connect   |
//Some other Stuff       |     SocketA->Callback from Async Connect
                         |     SocketA->Async Write
SocketB->Async Connect   |      
                         |     --> ?

现在,我必须承认我不太确定io_service是如何运作的。在第四行中,现在有两个不同的异步函数需要执行。

io_service是否能够同时执行Async ConnectAsync Write?如果是这种情况,很明显始终会调用首先完成的函数的回调。

如果io_service 能够这样做,它将以哪种顺序完成工作?如果首先调用SocketA Async Write,则首先调用它的回调。实际上,在SocketA的整个操作完成之前总会有效。

编辑:

根据ereOns的评论,我试着让我的问题更精确:

io_service线程的角度来看,SocketA Async Connect调用异步还是同步?从我的主线程的角度来看,它当然是异步的(它只是调度命令然后继续)。但是在io_service线程中,这个特定的Connect调用会阻止其他操作吗?

换句话说:一个io_service是否能够在另一个Socket上读取时连接到一个Socket?

另一个例子是,如果我只是在我的主函数中直接调用2 Async Connect

SocketA->AsyncConnect();
SocketB->AsyncConnect();

假设来自SocketA的主机有点慢,需要两秒钟才能回答。因此,当SocketA尝试连接时,SocketB会同时连接还是必须等到SocketA完成/超时?

2 个答案:

答案 0 :(得分:3)

所有工作都在io_service.run()运行的线程中完成。

但是,对任何async_方法的调用都不会阻止此特定线程:它的行为与io_service.run()在多个事件中调用select()的行为完全相同,每当引发这样的事件时,“返回”(调用回调)。也就是说,如果你打电话:

socketA->async_connect();
socketB->async_connect();

socketB也可以在socketA之前连接,然后首先调用相关的回调,仍然在线程io_service.run()运行。

这就是Boost Asio的美妙之处:在更合适的情况下,它需要非常谨慎地进行投票,等待和提升事件,让你处于“轻松”状态。

答案 1 :(得分:0)

您不应该尝试预测异步操作的执行顺序。 async_connect只是向io_service发出信号并立即返回。实际工作在io_service对象的事件处理循环(io_service::run)中完成,但您不知道确切的细节。它很可能使用特定于操作系统的异步IO功能。

目前尚不清楚你想要实现的目标。也许你应该使用同步操作。也许你应该使用线程同步功能。 也许io_service::run_one会帮助你(它最多只执行一个处理程序)。

也许你想在不同的线程中多次调用io_service::run,创建一个线程池。这样,一个长的完成处理程序将不会阻止所有其他处理程序。

boost::asio::io_service service;
const size_t ASIO_THREAD_COUNT = 3;
boost::thread_group threadGroup;
for (size_t i = 0; i < ASIO_THREAD_COUNT; ++i)
        threadGroup.create_thread(boost::bind(&boost::asio::io_service::run,
            &service, boost::system::error_code()));