Windows与类Unix平台上各种IO模型工作模式的讨论?

ngwsx 2008-04-07 10:13:26
我现在在移植nginx到Windows平台(现在把该版本的nginx称为ngwsx),
并对Windows上的各种IO模型都编写了相应的事件处理模块,
具体请到我的博客去看看:http://blog.csdn.net/ngwsx/

现在有个疑问,就是具体各种IO模型的工作模式是什么?

这里说的工作模式有两种:
Level Triggered (LT)(条件触发)
Edge Triggered (ET)(边缘触发)

Level Triggered 工作模式:
通过调用某种IO方法,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。
如果你不对该描述符作任何操作,当你再次调用该IO方法,内核还是会继续通知你的。

Edge Triggered 工作模式:
当描述符从未就绪变为就绪时,内核通过你调用IO方法时告诉你。然后它会假设你知道文件描述符已经就绪,
并且不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了
(比如,你在发送,接收或者接收请求,或者发送接收的数据少于一定量时导致了一个EWOULDBLOCK 错误)。
但是请注意,如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once)。

我想知道的是以下这些IO模型的工作模式是上面这两种的那一种,大家来讨论讨论吧。

Windows平台:
select
WSAAsyncSelect
WSAEventSelect
OverlappedIO
IO Completion Port
WSAPoll

类Unix平台:
select
poll
devpoll
epoll
kqueue
aio
eventport
rtsig

现在ngwsx是这样的工作模式:
(1)主线程通过调用select/WSAAsyncSelect/WSAEventSelect/OverlappedIO/IOCP/WSAPoll
这些函数来检测IO事件是否就绪或IO操作是否已经完成;如果已经准备好,
就投递相应的事件到内部一个队列中。
(2)多个工作线程同时从队列中取出事件并处理它。

因为这种工作模式,ngwsx要确保不能投递重复的事件到队列中,
所以需要了解各种IO模型的工作模式。
...全文
301 点赞 收藏 13
写回复
13 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
ngwsx 2011-04-09
新版本请在以下地址下载:
https://github.com/hehaiqiang/ngwsx/downloads
回复
星羽 2008-04-17
up
回复
ngwsx 2008-04-17
没人?
回复
ngwsx 2008-04-12
你是说具体实现吗?
那肯定不一样!
回复
michney 2008-04-11
[Quote=引用 8 楼 ngwsx 的回复:]
你说的这些我都有所了解,
EPOLL的工作模式ET与LT我也知道,
我就是通过EPOLL才知道这两种工作模式的,
我认为其它的IO模型也应该是具有这两种工作模式的一种或二种的?
就拿select来说吧,它应该是LT这种工作模式的,
当调用select检测到一个可读套接字描述符时,
然后如果不调用recv去读,
当下次调用select还是会检测到相同的可读套接字描述符。
poll也应该是LT工作模式,
Windows的IO完成端口应该是ET工作模式的。

[/Quote]
你这样理解也是可以的,但是select/poll, 就算是和epoll中的LT比还是有差距的
二者并不一样
回复
michney 2008-04-10
ET,LT是epoll里的
好像ET的性能更好,这个网上也有评估结果供参考
回复
michney 2008-04-10
这个还真不好说
这几天看开源的web server
感觉就是,linux 2.6以前的轻量级一般都选择poll/select,
性能高一点的都选择kqueue,现在2.6以后的一般都选择epoll
poll/select的缺点都是轮询,必须遍历所有点fd, 而且select监听fd还是有数量限制的
epoll是2.6以后的API,据说性能比poll高的相当多,
网上有这几种复用方式的评估结果,你可以参考一下
回复
ngwsx 2008-04-10
你说的这些我都有所了解,
EPOLL的工作模式ET与LT我也知道,
我就是通过EPOLL才知道这两种工作模式的,
我认为其它的IO模型也应该是具有这两种工作模式的一种或二种的?
就拿select来说吧,它应该是LT这种工作模式的,
当调用select检测到一个可读套接字描述符时,
然后如果不调用recv去读,
当下次调用select还是会检测到相同的可读套接字描述符。
poll也应该是LT工作模式,
Windows的IO完成端口应该是ET工作模式的。
其它的就不太确定。

虽然可以通过编写程序来了解所有这些IO模型的工作模式
但在这里希望对这些IO模型有过相关使用经验的朋友来说说。
回复
ngwsx 2008-04-10
这个不是我的创意,官方nginx就有的,不过它现在还不支持这种工作模式,
现在nginx是一个主进程多个工作进程这种模式,
如果比较两者的效率,那肯定是主线程多工作线程这种模式。

里面实现的事件队列是这样子的:


/* 首先ngx_event_t结构的定义是:*/

typedef struct ngx_event_s ngx_event_t;

struct ngx_event_s {
... /* 其它结构字段 */

ngx_event_t *next;
ngx_event_t **prev;
};


/* 这个互斥体用于保护事件队列 */
ngx_mutex_t *ngx_posted_events_mutex;
/*
* ngx_posted_events事件队列,官方nginx还有一个事件队列ngx_posted_accept_events。
*/
ngx_thread_volatile ngx_event_t *ngx_posted_events;


/* 事件入队 */

/*
* ev参数传入检测到的IO事件(用ngx_event_t结构变量来保存)的指针,
* queue参数传入ngx_posted_events的指针,也就是ngx_event_t二级指针。
*/

#define ngx_locked_post_event(ev, queue) \
\
if ((ev)->prev == NULL) { \
(ev)->next = (ngx_event_t *) *(queue); \
(ev)->prev = (ngx_event_t **) (queue); \
*(queue) = ev; \
\
if ((ev)->next) { \
(ev)->next->prev = &(ev)->next; \
} \
\
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, (ev)->log, 0, \
"post event %p", ev); \
\
} else { \
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, (ev)->log, 0, \
"update posted event %p", ev); \
}


#define ngx_post_event(ev, queue) \
\
ngx_mutex_lock(ngx_posted_events_mutex); \
ngx_locked_post_event(ev, queue); \
ngx_mutex_unlock(ngx_posted_events_mutex);


/* 事件出队 */

#define ngx_delete_posted_event(ev) \
\
*(ev)->prev = (ev)->next; \
\
if ((ev)->next) { \
(ev)->next->prev = (ev)->prev; \
} \
\
(ev)->prev = NULL; \
\
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, (ev)->log, 0, \
"delete posted event %p", ev);

回复
lovejklife 2008-04-09
我来说话,用SELECT好了,所有平台都有

(1)主线程通过调用select/WSAAsyncSelect/WSAEventSelect/OverlappedIO/IOCP/WSAPoll
这些函数来检测IO事件是否就绪或IO操作是否已经完成;如果已经准备好,
就投递相应的事件到内部一个队列中。
(2)多个工作线程同时从队列中取出事件并处理它。
你这个方法很有创意,效率如何
回复
独孤过儿 2008-04-09
跨平台的移植,一般都不敢随便说话的,何况还涉及到IO操作...
回复
ngwsx 2008-04-09
怎么没人发言呀,我发错地方吗?
回复
ngwsx 2008-04-08
谁来说说吗?
回复
相关推荐
发帖
工具平台和程序库
创建于2007-09-28

2.4w+

社区成员

C/C++ 工具平台和程序库
申请成为版主
帖子事件
创建了帖子
2008-04-07 10:13
社区公告
暂无公告