浏览 16204 次
锁定老帖子 主题:集成 IOCP 到 Libevent
该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2008-06-01
完整的代码在 http://spserver.googlecode.com/files/libevent-1.4.4-iocp-3.zip 2008.08.23 http://spserver.googlecode.com/files/libevent-1.4.5-stable-iocp-2.zip 增加了 non-blocking connect 的支持。 IOCP 是真正的异步 IO ,Libevent 提供的是一个 event-driven 的接口。 异步 IO 和 event-driven 的区别: 1.对于 event-driven,需要等待内核通知我们去启动一个IO操作,然后直接得到IO操作的结果 2.对于异步IO,我们可以随时无阻塞地启动 IO,然后由内核通知我们 IO 操作何时完成 要把 IOCP 集成到 libevent ,基本的思路是用 IOCP 模拟 event-driven 接口。 在 IOCP 中有一个特性,刚好可以用来模拟 event-driven 的接口:zero byte buffer recv/send。 当我们发起 WSARecv,WSASend 的时候,需要用 WSABUF 传递一个 buffer 进去。 如果我们把这个 buffer 设置为 zero byte ,那么当 socket 可读,或者可写的时候, 通过 GQCS 同样可以得到结果。这样就等于是模拟了 event-driven 的接口。 另一方面,Windows 的 WSAEventSelect 函数提供了一个 event-driven 的 accept 功能。 ... WSAEventSelect( listenFd, hEvent, FD_ACCEPT ); ... 问题在于如何把 IOCP 和 WSAEventSelect 集成起来。 通过查看 WSARecv,WSASend 的接口,可以注意到这两个接口都需要提供一个 OVERLAPPED 的结构体。 在这个结构体里有一个 hEvent 的成员。如果设置了这个 hEvent 参数,那么当这个 IO 请求完成的时候, hEvent 将会被 signal 。详细信息可以参考下面这个 URL : http://msdn.microsoft.com/en-us/library/ms742203(VS.85).aspx 引用 If the lpCompletionRoutine parameter is NULL, the hEvent parameter of lpOverlapped is signaled when the overlapped operation completes if it contains a valid event object handle. An application can use WSAWaitForMultipleEvents or WSAGetOverlappedResult to wait or poll on the event object.
这样看起来可以通过 WSAWaitForMultipleEvents 来集成 IOCP 和 WSAEventSelect 。 1.用 WSAEventSelect 来处理 accept event 2.用 IOCP 来处理 recv/send event ,发起 recv/send 请求的时候,设置 OVERLAPPED 的 hEvent 参数 3.把 WSAEventSelect 的 hEvent 和 IOCP 的 hEvent 收集起来,用 WSAWaitForMultipleEvents 统一处理 需要注意的时候,上述的第二步中,不需要为每个 recv/send 请求生成一个新的 hEvent, 而是所有的 recv/send 共用一个 hEvent 就行了。 在下面这个 URL 中提到,对于一个 hEvent 如果已经是 signal ,再次 signal ,不会有副作用。 http://msdn.microsoft.com/en-us/library/ms686211(VS.85).aspx 引用 Setting an event that is already set has no effect.
用代码来描述上面的这个思路,大概是下面这样。 首先创建 64 个 hEvent ,其中的 objects[0] 就用于 IOCP 中所有的 IO 操作。 其他剩余的 63 个 hEvent ,就可以用于 accept event 。 程序首先调用 WSAWaitForMultipleEvents 来等待 event 发生。 如果发现是 objects[0] 有事件,那么是 IOCP 的 IO 操作已经有完成的,就调用 GQCS 来处理。 如果发现是其他的 objects 有事件,那么就是有 accept event 发生。 /* objects[0] for iocp operations, object[1..63] for accept */ HANDLE objects[64]; struct event * accepts[64]; struct win32iocp_event event1; event1.overlapped.hEvent = objects[0]; WSARecv( ..., &event1.overlapped, ... ); .... struct win32iocp_event event2; event2.overlapped.hEvent = objects[0]; WSASend( ..., &event2.overlapped, ... ); ... WSAEventSelect( ev1->ev_fd, objects[1], FD_ACCEPT ); accepts[1] = ev1; ... WSAEventSelect( ev2->ev_fd, objects[2], FD_ACCEPT ); accepts[2] = ev2; ... int index = WSAWaitForMultipleEvents( 64, objects, FALSE, timeout, FALSE ); index = index - WSA_WAIT_EVENT_0; if( index > 0 ) { struct event * event = win32iocp_op->accepts[index]; event_active (event, EV_READ | EV_ACCEPT, 1); } if( index == 0 ) { for( ; ; ) { GetQueuedCompletionPort( ...... ); } } 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-06-03
近来 iunknown 写了很多用 iocp 的东东。请教一下能否比较一下 Linux 的 epoll 和 windows 的 iocp?
据我所知 Linux 是没有异步 IO 的,那么 epoll 应该相当于 iocp 之 socket 版本,能否论证一下? |
|
返回顶楼 | |
发表时间:2008-06-03
bigpanda 写道 近来 iunknown 写了很多用 iocp 的东东。请教一下能否比较一下 Linux 的 epoll 和 windows 的 iocp?
据我所知 Linux 是没有异步 IO 的,那么 epoll 应该相当于 iocp 之 socket 版本,能否论证一下? 对于 epoll 和 iocp 都算不上熟悉,只是根据自己的兴趣去找了一下资料来看,然后写了一些代码来验证一下自己的理解。就目前的测试来看,两者在高并发和 IO 性能方面,都是不错的。但依目前的经验,很难说已经测试到了它们各自的最优情况。对于这种高并发的性能测试,对于系统参数的调整也是一个很大的方面。如果要做具体的比较,那么需要列举具体的应用场景,具体把代码实现出来,才能做一个比较客观的对比。 Linux 没有异步 IO 应该说的是没有针对 socket 的异步 IO 吧?对于文件 IO 是有 AIO 这套接口的。 iocp 之 socket 版本?这个描述有点不解。 不过通常都是认为 linux 的 epoll 是和 windows 的 iocp 相对应的一种技术。两者常常会被相提并论,主要应该是两者都对高并发提供了良好的支持。但是从细节的角度来说,两者在 IO 模型上是不同的。epoll api 本身就只支持一种 event-driven 的模型,iocp api 除了 async IO 模型之外,如果使用 zero byte buffer 还可以支持 event-driven 的模型。 |
|
返回顶楼 | |
发表时间:2008-06-03
iunknown 写道 bigpanda 写道 近来 iunknown 写了很多用 iocp 的东东。请教一下能否比较一下 Linux 的 epoll 和 windows 的 iocp?
据我所知 Linux 是没有异步 IO 的,那么 epoll 应该相当于 iocp 之 socket 版本,能否论证一下? 对于 epoll 和 iocp 都算不上熟悉,只是根据自己的兴趣去找了一下资料来看,然后写了一些代码来验证一下自己的理解。就目前的测试来看,两者在高并发和 IO 性能方面,都是不错的。但依目前的经验,很难说已经测试到了它们各自的最优情况。对于这种高并发的性能测试,对于系统参数的调整也是一个很大的方面。如果要做具体的比较,那么需要列举具体的应用场景,具体把代码实现出来,才能做一个比较客观的对比。 Linux 没有异步 IO 应该说的是没有针对 socket 的异步 IO 吧?对于文件 IO 是有 AIO 这套接口的。 iocp 之 socket 版本?这个描述有点不解。 不过通常都是认为 linux 的 epoll 是和 windows 的 iocp 相对应的一种技术。两者常常会被相提并论,主要应该是两者都对高并发提供了良好的支持。但是从细节的角度来说,两者在 IO 模型上是不同的。epoll api 本身就只支持一种 event-driven 的模型,iocp api 除了 async IO 模型之外,如果使用 zero byte buffer 还可以支持 event-driven 的模型。 原来你就是讨论组内的那位stephen.nil阿 呵呵,真不错 |
|
返回顶楼 | |
发表时间:2008-06-04
SPServer是一个很不错的框架,受到启发,我用boost::asio实现了一个类似的框架,其中的一个特点,就是很容易在单线程和多线程之间切换,好像在您以前的文章中讨论过这个问题,
原理就是实现一个Wrap类,自动实现线程的传递 http://www.cppblog.com/eXile/archive/2008/06/04/51430.html#52178 |
|
返回顶楼 | |
发表时间:2008-06-05
linux/solaris上的aio有多种回调/通知方式,可能和libevent结合的最简单方式是signal,因为libevent也支持它,不过我没试过,在linux下用过的是内核线程直接写同步队列然后发送socket通知唤醒libevent去处理。solaris上可以用一个port专门处理aio通知,非常方便。虽然aio大部分时候用于处理文件IO,不过它和iocp应该有相似之处吧?iocp的细节我不清楚,如果是“完成-通知”或“完成-回调”方式,应该都可以和libevent结合。
|
|
返回顶楼 | |
发表时间:2008-06-05
GetQueuedCompletionStatusEx也支持超时,用它代替select也可以吧?试试移植一个iocp版本?
|
|
返回顶楼 | |
发表时间:2008-06-05
qiezi 写道 GetQueuedCompletionStatusEx也支持超时,用它代替select也可以吧?试试移植一个iocp版本?
GetQueuedCompletionStatusEx 和 GetQueuedCompletionStatus 的差别是前者可以一次得到多个 event 。 GetQueuedCompletionStatus 本身也支持超时的。 这里提到的要用 WSAWaitForMultipleEvents ,主要是解决 IOCP 和 WSAEventSelect 的集成。 在使用 libevent 的场景中,通常都需要把 accept,recv,send 这几个事件在同一个 event_base 里面来跑,因此集成 IOCP 和 WSAEventSelect 是很有必要的。如果不需要集成 accept 事件,那么只需要使用 zero byte buffer 就可以把 IOCP 当作 select 来用了。 这两天对 libevent 1.4.4 里面的单元测试案例进行了测试,发现了一个问题 http://msdn.microsoft.com/en-us/library/ms686358(VS.85).aspx 引用 Synchronization and Overlapped Input and Output
If an event is used, the hEvent member of the OVERLAPPED structure specifies a handle to the allocated event object. The system sets the state of the event object to nonsignaled when a call to the I/O function returns before the operation has been completed. 当多个 WSARecv/WSASend 使用同一个 Event 的时候,会产生 race condition 。 后来在 WSAWaitForMultipleEvents 之前,先调用一次 GetQueuedCompletionStatus ,这样可以消除这个 race condition 的影响。目前已经可以通过 regress.c 中大部分测试案例了。少部分失败的案例主要是由于环境的问题,现在是用 vc6 作为开发环境的,libevent 1.4.4 中的部分代码需要更高版本的 vs 。 最新的代码:http://spserver.googlecode.com/files/libevent-1.4.4-iocp-2.zip |
|
返回顶楼 | |
发表时间:2008-06-05
去找了 memcached for win32 的源代码,结果可以顺利编译,并且运行起来也很正常。
http://jehiah.cz/projects/memcached-win32/ 修改后的,libevent + iocp + memcached 代码下载 http://spserver.googlecode.com/files/memcached-1.2.1-iocp.zip http://spserver.googlecode.com/files/libevent-1.4.4-iocp-2.zip |
|
返回顶楼 | |
发表时间:2008-08-23
http://spserver.googlecode.com/files/libevent-1.4.5-stable-iocp-2.zip
最新的版本使用类似于解决 non-blocking accept 的方法实现了 non-blocking connect。 需要增加一个 EV_CONNECT 的标志位,增加了一个 conn_test 的例子来示范如何使用。 |
|
返回顶楼 | |