Linux async io 2
时间:2011-06-11 来源:freestyleking
async io 之iohandler实现
iohandler的功能:
1. 封装对fd的读写
2. delegate读写到io manager 线程
首先需要初始化iohandler.
用一个预先得到的fd作为参数打开对应文件,并设置nonblocking。
int open(int fd) {
m_fd = fd;
fcntl(m_fd, F_SETFL, O_NONBLOCK);
}
iohandler对外的读写接口不外乎read()和write(). 我们定义接口如下:
void async_read(Buffer *buf, int len, CB cb);
void async_write(Buffer *buf, int len, CB cb);
这里需要注意几点
1. 这里我们假设存在一种叫做Buffer的数据结构,它是对数据的封装。
2. 另外假设存在函数对象类型CB(CallBack),cb会在对写操作完成时调用。几乎可以说callback于async io是相生相伴的。一般来说,业务逻辑线程在调用完
async_read/async_write之后就很快结束了。对读写得到的数据或者说副作用的处理,全都需要封装在callback之中。也就是说业务逻辑需要意识要async io的
存在而参杂callback函数的代码。这是async io代码难以编写和维护,从而为人所诟病的地方。但是其实也是有办法将业务逻辑和async io完全分离开来。fiber技术的实现就是一个例子。
3. 函数返回void而不是通常情况下的int(以表示实际读写的数据量),这是因为这在async场景下无法做到。
由于是async操作,我们必须保存参数,以待实际读写时使用。所以,iohandler必须存在一些相应的内部数据成员。保存好参数后,需要把读写操作注册到io manager线程。
简单代码如下:
async_read(Buffer* buf, int len, CB cb){
m_readBuf = buf;
m_readLen = len;
m_readCB = cb;
m_events |= READ;
iomanager.addHandler(this);
}
async_write(Buffer * buf, int len, CB cb) {
m_writeBuf = buf;
m_writeLen = len;
m_writeCB = cb;
m_events |= WRITE;
write()
}
我们看到,async_read/async_write中没有做任何实际读写操作,所以我们还需要完成实际的数据读写函数。
void read();
void write();
这些函数酱油iomanager在检测到事件时调用。
read(){
m_total_read += readv(m_readLen - m_total_read);
if(m_total_read < m_readLen)
iomanager.addHandler(this);
else{
iomanager.removeHandler(this);
m_readCB();
}
}
write(){
m_total_write += writev(m_writeLen - m_total_write);
if(m_total_write < m_writeLen)
iomanager.addHandler(this);
else{
iomanager.removeHandler(this);
m_readCB();
}
}
以下是io manager中,addHandler和removeHandler的伪代码:
int addHandler(IOHandler *handler) {
struct epoll_event pe;
// 确保数据干净
memset(&pe, 0, sizeof(pe));
pe.data.fd = handler->m_fd;
if (handler->m_events & IO_EVENT_READ) {
pe.events |= EPOLLIN;
}
if (handler->m_events & IO_EVENT_WRITE) {
pe.events |= EPOLLOUT;
}
m_handlers[handler->m_fd] = handler;
rc = epoll_ctl(m_epollFD, EPOLL_CTL_MOD, handler->m_fd, &pe);
}
removeHandler 就更简单了,基本只要epoll_ctl(m_epollFD, EPOLL_CTL_DEL, handler->m_fd, &ep)和m_handlers[handler->m_fd] = NULL;
iohandler的功能:
1. 封装对fd的读写
2. delegate读写到io manager 线程
首先需要初始化iohandler.
用一个预先得到的fd作为参数打开对应文件,并设置nonblocking。
int open(int fd) {
m_fd = fd;
fcntl(m_fd, F_SETFL, O_NONBLOCK);
}
iohandler对外的读写接口不外乎read()和write(). 我们定义接口如下:
void async_read(Buffer *buf, int len, CB cb);
void async_write(Buffer *buf, int len, CB cb);
这里需要注意几点
1. 这里我们假设存在一种叫做Buffer的数据结构,它是对数据的封装。
2. 另外假设存在函数对象类型CB(CallBack),cb会在对写操作完成时调用。几乎可以说callback于async io是相生相伴的。一般来说,业务逻辑线程在调用完
async_read/async_write之后就很快结束了。对读写得到的数据或者说副作用的处理,全都需要封装在callback之中。也就是说业务逻辑需要意识要async io的
存在而参杂callback函数的代码。这是async io代码难以编写和维护,从而为人所诟病的地方。但是其实也是有办法将业务逻辑和async io完全分离开来。fiber技术的实现就是一个例子。
3. 函数返回void而不是通常情况下的int(以表示实际读写的数据量),这是因为这在async场景下无法做到。
由于是async操作,我们必须保存参数,以待实际读写时使用。所以,iohandler必须存在一些相应的内部数据成员。保存好参数后,需要把读写操作注册到io manager线程。
简单代码如下:
async_read(Buffer* buf, int len, CB cb){
m_readBuf = buf;
m_readLen = len;
m_readCB = cb;
m_events |= READ;
iomanager.addHandler(this);
}
async_write(Buffer * buf, int len, CB cb) {
m_writeBuf = buf;
m_writeLen = len;
m_writeCB = cb;
m_events |= WRITE;
write()
}
我们看到,async_read/async_write中没有做任何实际读写操作,所以我们还需要完成实际的数据读写函数。
void read();
void write();
这些函数酱油iomanager在检测到事件时调用。
read(){
m_total_read += readv(m_readLen - m_total_read);
if(m_total_read < m_readLen)
iomanager.addHandler(this);
else{
iomanager.removeHandler(this);
m_readCB();
}
}
write(){
m_total_write += writev(m_writeLen - m_total_write);
if(m_total_write < m_writeLen)
iomanager.addHandler(this);
else{
iomanager.removeHandler(this);
m_readCB();
}
}
以下是io manager中,addHandler和removeHandler的伪代码:
int addHandler(IOHandler *handler) {
struct epoll_event pe;
// 确保数据干净
memset(&pe, 0, sizeof(pe));
pe.data.fd = handler->m_fd;
if (handler->m_events & IO_EVENT_READ) {
pe.events |= EPOLLIN;
}
if (handler->m_events & IO_EVENT_WRITE) {
pe.events |= EPOLLOUT;
}
m_handlers[handler->m_fd] = handler;
rc = epoll_ctl(m_epollFD, EPOLL_CTL_MOD, handler->m_fd, &pe);
}
removeHandler 就更简单了,基本只要epoll_ctl(m_epollFD, EPOLL_CTL_DEL, handler->m_fd, &ep)和m_handlers[handler->m_fd] = NULL;
相关阅读 更多 +