一、异步通知的概念及作用
异步通知的意思是:一旦设备就绪,则主动通知应用程序,这一点非常类似于硬件上“中断”的概念。
信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。
信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。
二、Linux异步通知编程
1. Linux信号
在Linux中,异步通知使用信号来实现,Linux中可用的信号达30种,详见下表。
除了SIGSTOP和SIGKILL两个信号外,进程能够忽略或捕获其他的全部信号。
一个信号被捕获的意思是当一个信号到达时有相应的代码处理它。
2. 信号的接收
在用户程序中,为了捕获信号,可以使用signal()函数来设置对应信号的处理函数:
void {*signal(int signum, void (*handler)(int))}(int);
该函数原型较难理解,它可以分解为:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
第一个参数指定信号的值,第二个参数指定针对前面信号值的处理函数,
若为SIG_IGN,表示忽略该信号;若为SIG_DFL,表示采用系统默认方式处理信号;若为用户自定义的函数,则信号被捕获后,该函数将被执行。
3. 信号的释放
在设备驱动端,应该在合适的时机释放信号,这样用户端才能捕获到。
设备驱动的异步通知编程主要用到一项数据结构fasync_struct结构体,以及如下两个函数:
① 处理FASYNC标志变更的函数
int fasync_helper(int fd, struct file *filp, int mode, struct fasync_struct **fa);
② 释放信号用的函数
void kill_fasync(struct fasync_struct **fa, int sig, int band);
三、异步I/O
Linux中最常用的输入/输出模型是同步I/O。在这个模型中,当请求发出之后,应用程序就会阻塞,直到请求满足为止。
这是一种很好的解决方案,调用应用程序在等待I/O请求完成时不需要占用CPU。但是在有些应用场景中,需要使用到异步I/O,以提高CPU和I/O的吞吐率。
应用程序发起异步I/O动作后,直接开始执行,并不等待I/O结束,他要么过一段时间来查询之前的I/O请求完成情况,要么I/O请求完成了会自动被调用与I/O完成绑定的回调函数。
glibc的AIO主要包括如下函数:
-
aio_read(struct aiocb *aiocbp) // 请求对一个有效的文件描述符进行异步读操作。
-
aio_write(struct aiocb *aiocbp) // 请求对一个有效的文件描述符进行异步写操作。
-
aio_error(struct aiocb *aiocbp) // 确定请求的状态。
-
aio_return(struct aiocb *aiocbp) // 在异步I/O中,使用该函数返回状态。
-
aio_suspend(const struct aiocb *const cblist[], int n, const struct timespec *timeout) // 阻塞调用进程,直到异步请求完成为止。
-
aio_cancel(int fd, struct aiocb *aiocbp) // 取消对某个文件描述符执行的一个或所有I/O请求
-
lio_listio(int mode, struct aiocb *list[], int nent, struct sigevent *sig) // 同时发起多个传输。