aio_suspend函数方式
- 原理:aio_suspend函数允许程序暂停执行,直到一个或多个异步I/O请求完成。它接受一个指向aiocb结构数组的指针,以及数组中的元素数量,阻塞调用线程,直到指定的异步I/O操作中的任何一个完成。
- 优点:
- 简单直接,对于需要集中处理多个异步I/O完成事件的场景很方便。
- 不会产生信号处理函数带来的异步复杂性问题,例如重入问题。
- 缺点:
- 调用aio_suspend会阻塞调用线程,可能影响程序的并发性能,特别是在有其他需要并发执行的任务时。
- 灵活性相对较差,不能像信号驱动方式那样实时响应I/O完成事件。
- 适用场景:适用于对响应实时性要求不高,且希望集中处理多个异步I/O完成事件的场景,例如批量文件读取操作完成后的统一处理。
- 代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <aio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#define BUFFER_SIZE 1024
#define NUM_REQUESTS 3
int main() {
int i, fd;
char buffer[BUFFER_SIZE];
struct aiocb aiocb_list[NUM_REQUESTS];
for (i = 0; i < NUM_REQUESTS; i++) {
fd = open("testfile", O_RDONLY);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
aiocb_list[i].aio_fildes = fd;
aiocb_list[i].aio_buf = buffer;
aiocb_list[i].aio_nbytes = BUFFER_SIZE;
aiocb_list[i].aio_offset = i * BUFFER_SIZE;
aiocb_list[i].aio_sigevent.sigev_notify = SIGEV_NONE;
if (aio_read(&aiocb_list[i]) == -1) {
perror("aio_read");
close(fd);
exit(EXIT_FAILURE);
}
}
if (aio_suspend(aiocb_list, NUM_REQUESTS, NULL) == -1) {
perror("aio_suspend");
for (i = 0; i < NUM_REQUESTS; i++) {
aio_cancel(aiocb_list[i].aio_fildes, &aiocb_list[i]);
}
exit(EXIT_FAILURE);
}
for (i = 0; i < NUM_REQUESTS; i++) {
if (aio_error(&aiocb_list[i]) == 0) {
ssize_t bytes_read = aio_return(&aiocb_list[i]);
printf("Read %zd bytes in request %d\n", bytes_read, i);
} else {
perror("aio_error");
}
close(aiocb_list[i].aio_fildes);
}
return 0;
}
信号驱动的I/O完成通知方式
- 原理:通过设置
aiocb
结构中的aio_sigevent
成员,指定当异步I/O操作完成时发送的信号。程序通过安装信号处理函数来捕获该信号,在信号处理函数中处理I/O完成事件。
- 优点:
- 实时性强,I/O完成事件可以立即通过信号处理函数进行处理,不会阻塞主线程。
- 提高程序的并发性能,主线程可以继续执行其他任务。
- 缺点:
- 信号处理函数编写复杂,需要处理重入问题,因为信号处理函数可能在任何时候被调用。
- 信号处理函数的上下文与主线程上下文不同,可能需要额外的同步机制来共享数据。
- 适用场景:适用于对实时性要求高,需要及时响应I/O完成事件的场景,例如网络服务器在接收数据完成后立即处理。
- 代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <aio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#define BUFFER_SIZE 1024
#define NUM_REQUESTS 3
void io_completion_handler(int signum, siginfo_t *info, void *context) {
struct aiocb *aiocbp = (struct aiocb *)info->si_value.sival_ptr;
ssize_t bytes_read = aio_return(aiocbp);
if (bytes_read != -1) {
printf("Read %zd bytes\n", bytes_read);
} else {
perror("aio_return");
}
}
int main() {
int i, fd;
char buffer[BUFFER_SIZE];
struct aiocb aiocb_list[NUM_REQUESTS];
struct sigaction sa;
sa.sa_sigaction = io_completion_handler;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
perror("sigaction");
exit(EXIT_FAILURE);
}
for (i = 0; i < NUM_REQUESTS; i++) {
fd = open("testfile", O_RDONLY);
if (fd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
aiocb_list[i].aio_fildes = fd;
aiocb_list[i].aio_buf = buffer;
aiocb_list[i].aio_nbytes = BUFFER_SIZE;
aiocb_list[i].aio_offset = i * BUFFER_SIZE;
aiocb_list[i].aio_sigevent.sigev_notify = SIGEV_SIGNAL;
aiocb_list[i].aio_sigevent.sigev_signo = SIGUSR1;
aiocb_list[i].aio_sigevent.sigev_value.sival_ptr = &aiocb_list[i];
if (aio_read(&aiocb_list[i]) == -1) {
perror("aio_read");
close(fd);
exit(EXIT_FAILURE);
}
}
while (1) {
sleep(1);
}
return 0;
}