这段时间一直在学习Linux下编程,前两天看一帖子中提到Libeio这个异步I/O库,于是搜索来看看。libeio代码量不大用wc命令统计了一下,四千多行。于是乎决定学习一下,通过读代码来增加对linux编程的认识。
Libeio是用多线程实现的异步I/O库.主要步骤如下:
- 主线程接受请求,将请求放入请求队列,唤醒子线程处理。这里主线程不会阻塞,会继续接受请求
- 子线程处理请求,将请求回执放入回执队列,并调用用户自定义方法,通知主线程有请求已处理完毕
- 主线程处理回执。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <poll.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "eio.h"
int respipe [2];
/*
* 功能:子线程通知主线程已有回执放入回执队列.
*/
void
want_poll (void)
{
char dummy;
printf ("want_poll ()\n");
write (respipe [1], &dummy, 1);
}
/*
* 功能:主线程回执处理完毕,调用此函数
*/
void
done_poll (void)
{
char dummy;
printf ("done_poll ()\n");
read (respipe [0], &dummy, 1);
}
/*
* 功能:等到管道可读,处理回执信息
*/
void
event_loop (void)
{
// an event loop. yeah.
struct pollfd pfd;
pfd.fd = respipe [0];
pfd.events = POLLIN;
printf ("\nentering event loop\n");
while (eio_nreqs ())
{
poll (&pfd, 1, -1);
printf ("eio_poll () = %d\n", eio_poll ());
}
printf ("leaving event loop\n");
}
/*
* 功能:自定义函数,用户处理请求执行后的回执信息
*/
int
res_cb (eio_req *req)
{
printf ("res_cb(%d|%s) = %d\n", req->type, req->data ? req->data : "?", EIO_RESULT (req));
if (req->result < 0)
abort ();
return 0;
}
int
main (void)
{
printf ("pipe ()\n");
if (pipe (respipe))
abort ();
printf ("eio_init ()\n");
if (eio_init (want_poll, done_poll)) //初始化libeio库
abort ();
eio_mkdir ("eio-test-dir", 0777, 0, res_cb, "mkdir");
event_loop ();
return 0;
}
可以将demo.c与libeio一起编译,也可以先将libeio编译为动态链接库,然后demo.c与动态链接库一起编译。
执行流程图如下所示:
流程图详细步骤说明如下:
1、通过pipe函数创建管道。
管道主要作用是子线程告知父线程已有请求回执放入回执队列,父线程可以进行相应的处理。
2. libeio执行初始化操作。
调用eio_init执行初始化。eio_init函数声明:int eio_init (void (*want_poll)(void), void (*done_poll)(void))。eio_init参数是两个函数指针,want_poll和done_poll是成对出现。want_poll主要是子线程通知父线程已有请求处理完毕,done_poll则是在所有请求处理完毕后调用。
eio_init代码如下: