我使用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 Connect
和Async 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完成/超时?
答案 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()));