以嵌套或递归方式(即从处理程序内)调用asio :: io_service :: poll()或poll_one()是否有效?
一个真正基本的测试似乎暗示这是有效的(我只在一个平台上完成了测试)但我想确保从处理程序中再次调用poll()被认为是有效的行为。
我无法在asio文档中找到任何相关信息,所以我希望那些对asio内部工作有更多经验的人可以通过解释或参考来验证这一点。 / p>
基础测试:
struct NestedHandler
{
NestedHandler(std::string name, asio::io_service * service) :
name(name),
service(service)
{
// empty
}
void operator()()
{
std::cout << " { ";
std::cout << name;
std::cout << " ...calling poll again... ";
service->poll();
std::cout << " } ";
}
std::string name;
asio::io_service * service;
};
struct DefaultHandler
{
DefaultHandler(std::string name) :
name(name)
{
// empty
}
void operator()()
{
std::cout << " { ";
std::cout << name;
std::cout << " } ";
}
std::string name;
};
int main()
{
asio::io_service service;
service.post(NestedHandler("N",&service));
service.post(DefaultHandler("A"));
service.post(DefaultHandler("B"));
service.post(DefaultHandler("C"));
service.post(DefaultHandler("D"));
std::cout << "asio poll" << std::endl;
service.poll();
return 0;
}
// Output:
asio poll
{ N ...calling poll again... { A } { B } { C } { D } }
答案 0 :(得分:5)
这是有效的。
对于处理io_service
的函数系列,run()
是唯一有限制的函数:
不得从当前正在调用同一
run()
,run()
,run_one()
或poll()
之一的主题调用poll_one()
函数{1}}对象。
但是,我倾向于认为文档也应该包含io_service
的相同注释,因为嵌套调用可能导致它无限期地阻塞以下任何一种情况 [1] :
run_one()
中唯一的工作是当前正在执行的处理程序io_service
的并发提示为io_service
对于Windows I / O完成端口,在使用GetQueuedCompletionStatus()
为1
提供服务的所有线程中执行解复用。在高级别,调用io_service
的线程就像它们是线程池的一部分一样,允许操作系统将工作分配给每个线程。由于没有单个线程负责将操作解复用到其他线程,因此对GetQueuedCompletionStatus()
或poll()
的嵌套调用不会影响其他线程的操作调度。 documentation州:
使用I / O完成端口进行多路分解是在所有线程中执行的,这些线程呼叫
poll_one()
,io_service::run()
,io_service::run_one()
或io_service::poll()
。
对于所有其他解复用机制系统,服务io_service::poll_one()
的单个线程用于解复用I / O操作。确切的解复用机制可以在Platform-Specific Implementation Notes:
使用[
io_service
,/dev/poll
,epoll
,kqueue
]进行多路分解是在一个调用{{1}的线程中执行的},select
,io_service::run()
或io_service::run_one()
。
解复用机制的实现稍有不同,但处于高级别:
io_service::poll()
有一个主队列,线程使用该队列执行准备运行的操作io_service::poll_one()
都会在堆栈上创建一个私有队列,用于以无锁方式管理操作当io_service
为constructed时,可能会提供并发提示,表明实现应允许并发运行的线程数。当非I / O完成端口实现提供io_service
的并发提示时,它们被优化为尽可能多地使用专用队列并推迟与主队列的同步。例如,当通过io_service
发布处理程序时:
1
保证线程安全,以便在排队处理程序之前锁定主队列。当调用嵌套的post()
或io_service
时,必须将私有队列复制到主队列中,因为要执行的操作将从主队列中消耗。在implementation:
poll()
如果没有提供并发提示或除poll_one()
以外的任何值,则每次都将已发布的处理程序同步到主队列中。由于不需要复制专用队列,嵌套的// We want to support nested calls to poll() and poll_one(), so any handlers
// that are already on a thread-private queue need to be put on to the main
// queue now.
if (one_thread_)
if (thread_info* outer_thread_info = ctx.next_by_key())
op_queue_.push(outer_thread_info->private_op_queue);
和1
调用将正常运行。
1。在networking-ts draft中,请注意,不得从当前正在调用poll()
的线程调用poll_one()
。
答案 1 :(得分:1)
在嵌套或中调用asio :: io_service :: poll()或poll_one() 递归时(即从处理程序内)有效吗?
Sytaxically,这是有效的。但是,它在每个处理程序中都不好用,你应该运行poll()。此外,您的堆栈跟踪将增长到非常大的尺寸,并且您可能会遇到堆栈的大问题。