2013-08-02 17 views
3

我正在研究Windows上异步套接字I/O的选项。显然有不止一个选项:我可以使用WSASend ...以重叠结构提供完成回调或事件,或者我可以使用IOCP和(新)线程池。从我通常阅读,后面的选项是推荐的选项。我应该使用IOCP还是重叠WSASend/Receive?

但是,我不清楚为什么我应该使用IOCPs,如果完成例程足够满足我的目标:告诉套接字发送这个数据块并告诉我它是否完成。

我明白,IOCP的东西与CreateThreadpoolIo等组合使用操作系统线程池。但是,“正常”重叠的I/O也必须使用单独的线程?那么有什么区别/劣势?我的回调是由I/O线程调用并阻止其他内容?

由于提前, 克里斯托夫

回答

2

您可以使用,但对于服务器,IOCP与“完成队列”会有更好的表现,在一般情况下,因为它可以使用多个客户端<>服务器线程,无论是与CreateThreadpoolIo或一些用户空间线程池。很明显,在这种情况下,通常是专用的处理程序线程。

重叠的完成 - 例程I/O对客户更为有用,恕我直言。完成例程由排队等待发起I/O请求的线程(WSASend,WSARecv)的异步过程调用触发。这意味着该线程必须能够处理APC,并且通常这意味着围绕某个'blahEx()'调用一段时间(真)的循环。这非常有用,因为在阻塞队列或其他线程间信号上等待相当容易,从而允许向线程提供要发送的数据,并且完成例程总是由该线程处理。这个I/O机制使'hEvent'OVL参数免费使用 - 理想的是将通信缓冲区对象指针传递到完成例程。

应该避免使用实际的同步事件/信号量/重叠的hEvent参数的重叠I/O。

+0

为什么要避免同步事件? – nitzanms

0

Windows IOCP文档建议每个可用内核每个完成端口不要超过一个线程。超线程使核心数量翻倍。由于使用IOCP会导致出于事实驱动应用程序的所有实际目的,因此使用线程池会给调度程序添加不必要的处理。

如果你仔细考虑它,你就会明白为什么:一个事件应该尽可能快地完整服务(或者在初始处理后放置在某个队列中)。假设五个事件在四核计算机上排队到IOCP。如果有八个线程与IOCP相关联,那么您将面临调度程序中断一个事件的风险,即通过使用效率低下的另一个线程开始服务另一个事件。如果中断的螺纹位于关键部分内,也可能很危险。使用四个线程,您可以同时处理四个事件,只要一个事件完成,您就可以从IOCP队列中最后一个事件开始。

当然,您可能有用于非IOCP相关处理的线程池。

编辑 __ _ __ _ __ _ __ _ __ _ _

套接字(文件句柄工作也没关系)与IOCP关联。完成例程在IOCP上等待。一旦请求读取或写入套接字完成操作系统 - 通过IOCP - 释放等待IOCP的完成例程并返回您在调用读取或写入时提供的附加信息(我通常将指针传递给一个控制块)。所以完成程序立即“知道”在哪里找到与完成有关的信息。

如果您传递的是涉及控制块(类似)的信息,那么该控制块(可能)需要跟踪已完成的操作,以便知道下一步该做什么。 IOCP本身既不知道也不关心。

如果您正在编写连接到互联网的服务器,服务器将发出读取以等待客户端输入。该输入可能会在毫秒或一周后到达,当它输入时,IOCP将释放分析输入的完成例程。通常情况下,它会响应包含输入中请求的数据的写入,然后等待IOCP。写操作完成后,IOCP再次释放完成程序,该程序发现写操作已完成,通常会发出新读操作并开始新的循环。

因此,一个基于IOCP的应用程序通常会消耗非常少(或不)的CPU,直到完成发生时为止,此时完成例程完全倾斜,直到完成处理,发送新的I/O请求并再次等待在完成端口。除了IOCP超时(可以用来表示内务管理等)之外,所有I/O相关的事情都发生在操作系统中。

为了使事情进一步复杂化(或简化),使用WSA例程无需使用套接字,Win32函数ReadFile和WriteFile工作得很好。

+0

这一切都假设你的线程永远不会阻塞的工作(这将是理想的,但并不总是可行的)。如果线程CAN阻塞,在IOCP上等待额外的线程可以提供帮助;配置文件,看看。理想情况下,每个“连接”(完成键)对象都有自己的内部队列,这样如果你有自己的线程池可以帮助你确保你的I/O在共享池的其他潜在用户之前处理为同一个“连接”获得多个完成(读和写?),你不会使用两个IOCP线程并让它们在同一'连接'上作战...... –

+0

@Olof:所以你仍然会推荐IOCP重叠的I/O,但我应该将一个线程专用于完成端口。我有这个权利吗?并不限制我应该与端口关联的句柄数量(使用'ExistingCompletionPort'参数)? – Christoph

+0

IOCP重叠I/O,但它们比等待多个对象(本质上是一种轮询形式)更有效。在系统中,应该没有更多的线程等待IOCP,而不是核心(超线程核心数为2)。所以如果你有四个内核,你不应该有超过四个线程等待IOCP。当然,如果你有两个IOCP,那么你不应该有多于四个线程(也许可以像我一样调整线程优先级)。 –

相关问题