io_cancel 函数详解
1. 函数介绍
2. 函数原型
c
#include <linux/aio_abi.h>
int io_cancel(aio_context_t ctx_id, struct iocb *iocb, struct io_event *result);
3. 功能
4. 参数
- aio_context_t ctx_id: AIO上下文ID(由io_setup创建)
- *struct iocb iocb: 要取消的异步I/O控制块指针
- *struct io_event result: 用于存储取消结果的事件结构指针
5. 返回值
- 成功: 返回0
- 失败: 返回负的错误码
6. 相似函数,或关联函数
7. 示例代码
示例1:基础io_cancel使用
c
#include <linux/aio_abi.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
/**
* 系统调用包装函数
*/
static inline int io_setup(unsigned nr_events, aio_context_t *ctxp) {
return syscall(__NR_io_setup, nr_events, ctxp);
}
static inline int io_destroy(aio_context_t ctx) {
return syscall(__NR_io_destroy, ctx);
}
static inline int io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp) {
return syscall(__NR_io_submit, ctx, nr, iocbpp);
}
static inline int io_cancel(aio_context_t ctx, struct iocb *iocb, struct io_event *result) {
return syscall(__NR_io_cancel, ctx, iocb, result);
}
static inline int io_getevents(aio_context_t ctx, long min_nr, long nr,
struct io_event *events, struct timespec *timeout) {
return syscall(__NR_io_getevents, ctx, min_nr, nr, events, timeout);
}
/**
* 演示基础io_cancel使用方法
*/
int demo_io_cancel_basic() {
aio_context_t ctx;
struct iocb iocb;
struct io_event result;
int fd;
int ret;
printf("=== 基础io_cancel使用示例 ===\n");
// 初始化AIO上下文
printf("1. 初始化AIO上下文:\n");
ctx = 0;
ret = io_setup(128, &ctx);
if (ret < 0) {
printf(" 初始化AIO上下文失败: %s\n", strerror(-ret));
return -1;
}
printf(" ✓ AIO上下文初始化成功\n");
printf(" 上下文ID: %llu\n", (unsigned long long)ctx);
// 创建测试文件
printf("\n2. 创建测试文件:\n");
const char *filename = "aio_cancel_test.txt";
fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
perror(" 创建测试文件失败");
io_destroy(ctx);
return -1;
}
printf(" ✓ 测试文件创建成功: %s\n", filename);
// 准备异步写入操作
printf("\n3. 准备异步写入操作:\n");
char *test_data = "This is test data for AIO cancel operation.\n";
size_t data_size = strlen(test_data);
// 初始化iocb结构
memset(&iocb, 0, sizeof(iocb));
iocb.aio_data = 12345; // 用户数据
iocb.aio_key = 0;
iocb.aio_rw_flags = 0;
iocb.aio_lio_opcode = IOCB_CMD_PWRITE; // 异步写入
iocb.aio_reqprio = 0;
iocb.aio_fildes = fd;
iocb.aio_buf = (uint64_t)(uintptr_t)test_data;
iocb.aio_nbytes = data_size;
iocb.aio_offset = 0;
iocb.aio_flags = 0;
iocb.aio_resfd = 0;
printf(" 准备异步写入操作:\n");
printf(" 文件描述符: %d\n", fd);
printf(" 数据大小: %zu 字节\n", data_size);
printf(" 用户数据: %llu\n", (unsigned long long)iocb.aio_data);
// 提交异步操作
printf("\n4. 提交异步操作:\n");
struct iocb *iocbs[1] = {&iocb};
ret = io_submit(ctx, 1, iocbs);
if (ret != 1) {
printf(" 提交异步操作失败: %s\n", strerror(-ret));
close(fd);
unlink(filename);
io_destroy(ctx);
return -1;
}
printf(" ✓ 异步操作提交成功\n");
// 立即尝试取消操作
printf("\n5. 立即尝试取消操作:\n");
ret = io_cancel(ctx, &iocb, &result);
if (ret == 0) {
printf(" ✓ 操作取消成功\n");
printf(" 取消结果:\n");
printf(" 用户数据: %llu\n", (unsigned long long)result.data);
printf(" 结果: %ld\n", result.res);
printf(" 结果2: %ld\n", result.res2);
if (result.res == -ECANCELED) {
printf(" 状态: 操作已取消 (ECANCELED)\n");
}
} else if (ret == -EAGAIN) {
printf(" ℹ 操作无法取消 (可能已开始执行或已完成)\n");
// 等待操作完成
printf(" 等待操作完成...\n");
struct io_event events[1];
ret = io_getevents(ctx, 1, 1, events, NULL);
if (ret > 0) {
printf(" ✓ 操作完成\n");
printf(" 用户数据: %llu\n", (unsigned long long)events[0].data);
printf(" 结果: %ld 字节\n", events[0].res);
}
} else {
printf(" ✗ 取消操作失败: %s\n", strerror(-ret));
}
// 演示延时取消
printf("\n6. 演示延时取消:\n");
// 创建一个更大的写入操作
char *large_data = malloc(1024 * 1024); // 1MB数据
if (large_data) {
// 填充数据
for (int i = 0; i < 1024 * 1024; i++) {
large_data[i] = 'A' + (i % 26);
}
// 准备新的iocb
struct iocb large_iocb;
memset(&large_iocb, 0, sizeof(large_iocb));
large_iocb.aio_data = 54321;
large_iocb.aio_lio_opcode = IOCB_CMD_PWRITE;
large_iocb.aio_fildes = fd;
large_iocb.aio_buf = (uint64_t)(uintptr_t)large_data;
large_iocb.aio_nbytes = 1024 * 1024;
large_iocb.aio_offset = data_size; // 在之前数据之后
printf(" 准备大块数据写入操作 (1MB)\n");
struct iocb *large_iocbs[1] = {&large_iocb};
ret = io_submit(ctx, 1, large_iocbs);
if (ret == 1) {
printf(" ✓ 大块数据写入操作提交成功\n");
// 短暂延迟后尝试取消
printf(" 等待100ms后尝试取消...\n");
usleep(100000); // 100ms
struct io_event cancel_result;
ret = io_cancel(ctx, &large_iocb, &cancel_result);
if (ret == 0) {
printf(" ✓ 大块数据写入操作取消成功\n");
} else if (ret == -EAGAIN) {
printf(" ℹ 大块数据写入操作无法取消\n");
// 等待操作完成
struct io_event events[1];
int wait_ret = io_getevents(ctx, 1, 1, events, NULL);
if (wait_ret > 0) {
printf(" ✓ 大块数据写入完成: %ld 字节\n", events[0].res);
}
} else {
printf(" ✗ 取消大块数据写入失败: %s\n", strerror(-ret));
}
}
free(large_data);
}
// 清理资源
printf("\n7. 清理资源:\n");
close(fd);
unlink(filename);
io_destroy(ctx);
printf(" ✓ 资源清理完成\n");
return 0;
}
int main() {
return demo_io_cancel_basic();
}
示例2:批量操作取消
c
#include <linux/aio_abi.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
/**
* 系统调用包装函数
*/
static inline int io_setup(unsigned nr_events, aio_context_t *ctxp) {
return syscall(__NR_io_setup, nr_events, ctxp);
}
static inline int io_destroy(aio_context_t ctx) {
return syscall(__NR_io_destroy, ctx);
}
static inline int io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp) {
return syscall(__NR_io_submit, ctx, nr, iocbpp);
}
static inline int io_cancel(aio_context_t ctx, struct iocb *iocb, struct io_event *result) {
return syscall(__NR_io_cancel, ctx, iocb, result);
}
static inline int io_getevents(aio_context_t ctx, long min_nr, long nr,
struct io_event *events, struct timespec *timeout) {
return syscall(__NR_io_getevents, ctx, min_nr, nr, events, timeout);
}
/**
* 批量操作取消演示
*/
int demo_batch_cancel() {
aio_context_t ctx;
const int batch_size = 8;
struct iocb iocbs[batch_size];
struct io_event results[batch_size];
int fd;
int ret;
char *test_files[batch_size];
printf("=== 批量操作取消演示 ===\n");
// 初始化AIO上下文
printf("1. 初始化AIO上下文:\n");
ctx = 0;
ret = io_setup(128, &ctx);
if (ret < 0) {
printf(" 初始化AIO上下文失败: %s\n", strerror(-ret));
return -1;
}
printf(" ✓ AIO上下文初始化成功\n");
// 创建测试文件
printf("\n2. 创建测试文件:\n");
for (int i = 0; i < batch_size; i++) {
char filename[32];
snprintf(filename, sizeof(filename), "batch_cancel_%d.txt", i);
test_files[i] = strdup(filename);
fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd != -1) {
// 写入一些初始数据使文件不为空
char initial_data[256];
memset(initial_data, 'A' + i, sizeof(initial_data) - 1);
initial_data[sizeof(initial_data) - 1] = '\0';
write(fd, initial_data, sizeof(initial_data) - 1);
close(fd);
printf(" 创建测试文件 %d: %s\n", i, filename);
}
}
// 准备批量异步读取操作
printf("\n3. 准备批量异步读取操作:\n");
struct iocb *iocb_ptrs[batch_size];
for (int i = 0; i < batch_size; i++) {
fd = open(test_files[i], O_RDONLY);
if (fd == -1) {
printf(" 打开文件 %s 失败\n", test_files[i]);
continue;
}
// 初始化iocb
memset(&iocbs[i], 0, sizeof(iocbs[i]));
iocbs[i].aio_data = i + 1; // 使用索引作为用户数据
iocbs[i].aio_lio_opcode = IOCB_CMD_PREAD;
iocbs[i].aio_fildes = fd;
// 分配读取缓冲区
char *read_buffer = malloc(1024);
if (read_buffer) {
iocbs[i].aio_buf = (uint64_t)(uintptr_t)read_buffer;
iocbs[i].aio_nbytes = 1024;
iocbs[i].aio_offset = 0;
}
iocb_ptrs[i] = &iocbs[i];
printf(" 准备读取操作 %d: 文件 %s\n", i + 1, test_files[i]);
}
// 提交批量操作
printf("\n4. 提交批量异步操作:\n");
ret = io_submit(ctx, batch_size, iocb_ptrs);
if (ret < 0) {
printf(" 提交批量操作失败: %s\n", strerror(-ret));
goto cleanup;
}
printf(" ✓ 成功提交 %d 个异步操作\n", ret);
// 演示部分取消
printf("\n5. 演示部分操作取消:\n");
int cancel_count = 0;
for (int i = 0; i < batch_size; i += 2) { // 取消偶数索引的操作
ret = io_cancel(ctx, &iocbs[i], &results[cancel_count]);
if (ret == 0) {
printf(" ✓ 操作 %d 取消成功\n", (int)iocbs[i].aio_data);
cancel_count++;
} else if (ret == -EAGAIN) {
printf(" ℹ 操作 %d 无法取消 (可能已开始执行)\n", (int)iocbs[i].aio_data);
} else {
printf(" ✗ 操作 %d 取消失败: %s\n", (int)iocbs[i].aio_data, strerror(-ret));
}
}
printf(" 总共尝试取消 %d 个操作\n", cancel_count);
// 等待剩余操作完成
printf("\n6. 等待剩余操作完成:\n");
struct io_event completed_events[batch_size];
int completed_count = 0;
// 等待最多5秒
struct timespec timeout = {5, 0};
ret = io_getevents(ctx, 1, batch_size, completed_events, &timeout);
if (ret > 0) {
printf(" ✓ 收到 %d 个完成事件\n", ret);
completed_count = ret;
for (int i = 0; i < ret; i++) {
printf(" 操作 %llu 完成: %ld 字节\n",
(unsigned long long)completed_events[i].data,
completed_events[i].res);
}
} else if (ret == 0) {
printf(" ⚠ 超时,没有收到完成事件\n");
} else {
printf(" ✗ 等待完成事件失败: %s\n", strerror(-ret));
}
// 显示取消结果
printf("\n7. 取消结果统计:\n");
printf(" 尝试取消的操作数: %d\n", cancel_count);
printf(" 完成的操作数: %d\n", completed_count);
printf(" 总操作数: %d\n", batch_size);
// 清理资源
cleanup:
printf("\n8. 清理资源:\n");
// 关闭文件描述符和释放缓冲区
for (int i = 0; i < batch_size; i++) {
if (iocbs[i].aio_fildes > 0) {
close(iocbs[i].aio_fildes);
}
if (iocbs[i].aio_buf) {
free((void*)(uintptr_t)iocbs[i].aio_buf);
}
if (test_files[i]) {
unlink(test_files[i]);
free(test_files[i]);
}
}
io_destroy(ctx);
printf(" ✓ 所有资源清理完成\n");
return 0;
}
int main() {
return demo_batch_cancel();
}
示例3:超时取消机制
c
#include <linux/aio_abi.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <signal.h>
/**
* 系统调用包装函数
*/
static inline int io_setup(unsigned nr_events, aio_context_t *ctxp) {
return syscall(__NR_io_setup, nr_events, ctxp);
}
static inline int io_destroy(aio_context_t ctx) {
return syscall(__NR_io_destroy, ctx);
}
static inline int io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp) {
return syscall(__NR_io_submit, ctx, nr, iocbpp);
}
static inline int io_cancel(aio_context_t ctx, struct iocb *iocb, struct io_event *result) {
return syscall(__NR_io_cancel, ctx, iocb, result);
}
static inline int io_getevents(aio_context_t ctx, long min_nr, long nr,
struct io_event *events, struct timespec *timeout) {
return syscall(__NR_io_getevents, ctx, min_nr, nr, events, timeout);
}
/**
* 超时取消上下文
*/
typedef struct {
aio_context_t ctx;
struct iocb *iocb;
int is_completed;
int is_cancelled;
time_t start_time;
int timeout_seconds;
} timeout_cancel_ctx_t;
/**
* 超时处理函数
*/
void timeout_handler(int sig) {
printf("收到超时信号\n");
}
/**
* 演示超时取消机制
*/
int demo_timeout_cancel_mechanism() {
aio_context_t ctx;
struct iocb iocb;
struct io_event result;
int fd;
int ret;
printf("=== 超时取消机制演示 ===\n");
// 初始化AIO上下文
printf("1. 初始化AIO上下文:\n");
ctx = 0;
ret = io_setup(64, &ctx);
if (ret < 0) {
printf(" 初始化AIO上下文失败: %s\n", strerror(-ret));
return -1;
}
printf(" ✓ AIO上下文初始化成功\n");
// 创建测试文件
printf("\n2. 创建测试文件:\n");
const char *filename = "timeout_test.txt";
fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
perror(" 创建测试文件失败");
io_destroy(ctx);
return -1;
}
// 写入大量数据
char *large_data = malloc(10 * 1024 * 1024); // 10MB数据
if (large_data) {
for (int i = 0; i < 10 * 1024 * 1024; i++) {
large_data[i] = 'A' + (i % 26);
}
write(fd, large_data, 10 * 1024 * 1024);
}
close(fd);
printf(" ✓ 创建了10MB测试文件: %s\n", filename);
// 重新打开文件进行读取
fd = open(filename, O_RDONLY);
if (fd == -1) {
perror(" 打开测试文件失败");
io_destroy(ctx);
unlink(filename);
return -1;
}
// 准备长时间读取操作
printf("\n3. 准备长时间读取操作:\n");
char *read_buffer = malloc(5 * 1024 * 1024); // 5MB缓冲区
if (!read_buffer) {
perror(" 分配读取缓冲区失败");
close(fd);
io_destroy(ctx);
unlink(filename);
return -1;
}
// 初始化iocb
memset(&iocb, 0, sizeof(iocb));
iocb.aio_data = 99999;
iocb.aio_lio_opcode = IOCB_CMD_PREAD;
iocb.aio_fildes = fd;
iocb.aio_buf = (uint64_t)(uintptr_t)read_buffer;
iocb.aio_nbytes = 5 * 1024 * 1024; // 读取5MB
iocb.aio_offset = 0;
printf(" 准备读取5MB数据\n");
// 提交异步读取操作
struct iocb *iocbs[1] = {&iocb};
ret = io_submit(ctx, 1, iocbs);
if (ret != 1) {
printf(" 提交异步读取操作失败: %s\n", strerror(-ret));
free(read_buffer);
close(fd);
io_destroy(ctx);
unlink(filename);
return -1;
}
printf(" ✓ 异步读取操作提交成功\n");
// 设置超时处理
printf("\n4. 设置超时处理:\n");
time_t start_time = time(NULL);
const int timeout_seconds = 3;
printf(" 设置超时时间: %d 秒\n", timeout_seconds);
// 等待操作完成或超时
printf("\n5. 等待操作完成或超时:\n");
struct io_event events[1];
struct timespec timeout = {1, 0}; // 1秒超时
int operation_completed = 0;
int cancel_attempted = 0;
while (difftime(time(NULL), start_time) < timeout_seconds) {
ret = io_getevents(ctx, 0, 1, events, &timeout);
if (ret > 0) {
printf(" ✓ 操作在超时前完成\n");
printf(" 读取字节数: %ld\n", events[0].res);
operation_completed = 1;
break;
} else if (ret == 0) {
printf(" 操作仍在进行中...\n");
// 每秒检查一次是否需要取消
if (!cancel_attempted && difftime(time(NULL), start_time) >= 2) {
printf(" 2秒后尝试取消操作\n");
struct io_event cancel_result;
ret = io_cancel(ctx, &iocb, &cancel_result);
if (ret == 0) {
printf(" ✓ 操作取消成功\n");
cancel_attempted = 1;
break;
} else if (ret == -EAGAIN) {
printf(" ℹ 操作无法取消\n");
cancel_attempted = 1;
} else {
printf(" ✗ 取消操作失败: %s\n", strerror(-ret));
cancel_attempted = 1;
}
}
} else {
printf(" ✗ 等待事件失败: %s\n", strerror(-ret));
break;
}
}
// 超时后的处理
if (!operation_completed && !cancel_attempted) {
printf("\n6. 超时处理:\n");
printf(" 操作超时 (%d 秒)\n", timeout_seconds);
// 强制取消操作
printf(" 强制取消操作...\n");
struct io_event cancel_result;
ret = io_cancel(ctx, &iocb, &cancel_result);
if (ret == 0) {
printf(" ✓ 操作取消成功\n");
} else if (ret == -EAGAIN) {
printf(" ℹ 操作无法取消\n");
} else {
printf(" ✗ 取消操作失败: %s\n", strerror(-ret));
}
}
// 等待最终结果
printf("\n7. 等待最终结果:\n");
timeout.tv_sec = 2; // 2秒超时
timeout.tv_nsec = 0;
ret = io_getevents(ctx, 0, 1, events, &timeout);
if (ret > 0) {
printf(" 最终结果:\n");
printf(" 用户数据: %llu\n", (unsigned long long)events[0].data);
printf(" 结果: %ld\n", events[0].res);
if (events[0].res == -ECANCELED) {
printf(" 状态: 操作已取消\n");
} else if (events[0].res < 0) {
printf(" 错误: %s\n", strerror(-events[0].res));
} else {
printf(" 成功读取: %ld 字节\n", events[0].res);
}
} else if (ret == 0) {
printf(" 超时,无结果返回\n");
} else {
printf(" 等待结果失败: %s\n", strerror(-ret));
}
// 清理资源
printf("\n8. 清理资源:\n");
free(read_buffer);
close(fd);
unlink(filename);
io_destroy(ctx);
printf(" ✓ 资源清理完成\n");
return 0;
}
int main() {
return demo_timeout_cancel_mechanism();
}
示例4:条件取消策略
c
#include <linux/aio_abi.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <pthread.h>
/**
* 系统调用包装函数
*/
static inline int io_setup(unsigned nr_events, aio_context_t *ctxp) {
return syscall(__NR_io_setup, nr_events, ctxp);
}
static inline int io_destroy(aio_context_t ctx) {
return syscall(__NR_io_destroy, ctx);
}
static inline int io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp) {
return syscall(__NR_io_submit, ctx, nr, iocbpp);
}
static inline int io_cancel(aio_context_t ctx, struct iocb *iocb, struct io_event *result) {
return syscall(__NR_io_cancel, ctx, iocb, result);
}
static inline int io_getevents(aio_context_t ctx, long min_nr, long nr,
struct io_event *events, struct timespec *timeout) {
return syscall(__NR_io_getevents, ctx, min_nr, nr, events, timeout);
}
/**
* 取消策略枚举
*/
typedef enum {
CANCEL_STRATEGY_IMMEDIATE, // 立即取消
CANCEL_STRATEGY_TIMEOUT, // 超时取消
CANCEL_STRATEGY_CONDITIONAL, // 条件取消
CANCEL_STRATEGY_NEVER // 从不取消
} cancel_strategy_t;
/**
* 操作上下文
*/
typedef struct {
struct iocb iocb;
int is_submitted;
int is_completed;
int is_cancelled;
time_t submit_time;
cancel_strategy_t strategy;
int timeout_seconds;
int condition_value;
} operation_context_t;
/**
* 条件取消检查函数
*/
int check_cancel_condition(operation_context_t *ctx) {
switch (ctx->strategy) {
case CANCEL_STRATEGY_IMMEDIATE:
return 1; // 立即取消
case CANCEL_STRATEGY_TIMEOUT:
if (difftime(time(NULL), ctx->submit_time) > ctx->timeout_seconds) {
printf(" 操作超时,触发取消\n");
return 1;
}
return 0;
case CANCEL_STRATEGY_CONDITIONAL:
// 模拟条件检查
if (ctx->condition_value > 100) {
printf(" 条件满足,触发取消\n");
return 1;
}
return 0;
case CANCEL_STRATEGY_NEVER:
default:
return 0;
}
}
/**
* 演示条件取消策略
*/
int demo_conditional_cancel_strategy() {
aio_context_t ctx;
operation_context_t operations[5];
int fd;
int ret;
printf("=== 条件取消策略演示 ===\n");
// 初始化AIO上下文
printf("1. 初始化AIO上下文:\n");
ctx = 0;
ret = io_setup(64, &ctx);
if (ret < 0) {
printf(" 初始化AIO上下文失败: %s\n", strerror(-ret));
return -1;
}
printf(" ✓ AIO上下文初始化成功\n");
// 创建测试文件
printf("\n2. 创建测试文件:\n");
const char *filename = "conditional_cancel_test.txt";
fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
perror(" 创建测试文件失败");
io_destroy(ctx);
return -1;
}
// 写入测试数据
char *test_data = malloc(1024 * 1024); // 1MB数据
if (test_data) {
for (int i = 0; i < 1024 * 1024; i++) {
test_data[i] = 'A' + (i % 26);
}
write(fd, test_data, 1024 * 1024);
}
close(fd);
free(test_data);
printf(" ✓ 创建了1MB测试文件: %s\n", filename);
// 重新打开文件进行读取
fd = open(filename, O_RDONLY);
if (fd == -1) {
perror(" 打开测试文件失败");
io_destroy(ctx);
unlink(filename);
return -1;
}
// 初始化操作上下文
printf("\n3. 初始化操作上下文:\n");
for (int i = 0; i < 5; i++) {
operation_context_t *op_ctx = &operations[i];
memset(op_ctx, 0, sizeof(*op_ctx));
// 设置不同的取消策略
switch (i % 4) {
case 0:
op_ctx->strategy = CANCEL_STRATEGY_IMMEDIATE;
printf(" 操作 %d: 立即取消策略\n", i + 1);
break;
case 1:
op_ctx->strategy = CANCEL_STRATEGY_TIMEOUT;
op_ctx->timeout_seconds = 2; // 2秒超时
printf(" 操作 %d: 超时取消策略 (2秒)\n", i + 1);
break;
case 2:
op_ctx->strategy = CANCEL_STRATEGY_CONDITIONAL;
op_ctx->condition_value = i * 50; // 不同的条件值
printf(" 操作 %d: 条件取消策略 (条件值: %d)\n", i + 1, op_ctx->condition_value);
break;
case 3:
op_ctx->strategy = CANCEL_STRATEGY_NEVER;
printf(" 操作 %d: 从不取消策略\n", i + 1);
break;
}
}
// 准备异步读取操作
printf("\n4. 准备异步读取操作:\n");
struct iocb *iocb_ptrs[5];
for (int i = 0; i < 5; i++) {
operation_context_t *op_ctx = &operations[i];
// 初始化iocb
memset(&op_ctx->iocb, 0, sizeof(op_ctx->iocb));
op_ctx->iocb.aio_data = i + 1;
op_ctx->iocb.aio_lio_opcode = IOCB_CMD_PREAD;
op_ctx->iocb.aio_fildes = fd;
// 分配读取缓冲区
char *read_buffer = malloc(200 * 1024); // 200KB缓冲区
if (read_buffer) {
op_ctx->iocb.aio_buf = (uint64_t)(uintptr_t)read_buffer;
op_ctx->iocb.aio_nbytes = 200 * 1024;
op_ctx->iocb.aio_offset = i * 200 * 1024; // 不同的偏移量
iocb_ptrs[i] = &op_ctx->iocb;
op_ctx->is_submitted = 1;
op_ctx->submit_time = time(NULL);
printf(" 准备操作 %d: 读取200KB数据\n", i + 1);
}
}
// 提交异步操作
printf("\n5. 提交异步操作:\n");
ret = io_submit(ctx, 5, iocb_ptrs);
if (ret < 0) {
printf(" 提交异步操作失败: %s\n", strerror(-ret));
goto cleanup;
}
printf(" ✓ 成功提交 %d 个异步操作\n", ret);
// 执行取消策略
printf("\n6. 执行取消策略:\n");
time_t start_time = time(NULL);
int completed_operations = 0;
int cancelled_operations = 0;
// 监控和取消操作
while (difftime(time(NULL), start_time) < 10) { // 最多等待10秒
// 检查取消条件
for (int i = 0; i < 5; i++) {
operation_context_t *op_ctx = &operations[i];
if (op_ctx->is_submitted && !op_ctx->is_completed && !op_ctx->is_cancelled) {
if (check_cancel_condition(op_ctx)) {
printf(" 尝试取消操作 %d\n", i + 1);
struct io_event cancel_result;
ret = io_cancel(ctx, &op_ctx->iocb, &cancel_result);
if (ret == 0) {
printf(" ✓ 操作 %d 取消成功\n", i + 1);
op_ctx->is_cancelled = 1;
cancelled_operations++;
} else if (ret == -EAGAIN) {
printf(" ℹ 操作 %d 无法取消\n", i + 1);
} else {
printf(" ✗ 操作 %d 取消失败: %s\n", i + 1, strerror(-ret));
}
}
}
}
// 检查完成事件
struct io_event events[5];
struct timespec timeout = {0, 100000000}; // 100ms超时
ret = io_getevents(ctx, 0, 5, events, &timeout);
if (ret > 0) {
printf(" 收到 %d 个完成事件\n", ret);
for (int i = 0; i < ret; i++) {
int op_index = events[i].data - 1;
if (op_index >= 0 && op_index < 5) {
operation_context_t *op_ctx = &operations[op_index];
op_ctx->is_completed = 1;
completed_operations++;
printf(" 操作 %d 完成: %ld 字节\n",
op_index + 1, events[i].res);
}
}
}
// 检查是否所有操作都已完成或取消
int all_done = 1;
for (int i = 0; i < 5; i++) {
operation_context_t *op_ctx = &operations[i];
if (op_ctx->is_submitted && !op_ctx->is_completed && !op_ctx->is_cancelled) {
all_done = 0;
break;
}
}
if (all_done) {
printf(" 所有操作已完成或取消\n");
break;
}
// 更新条件值(模拟条件变化)
for (int i = 0; i < 5; i++) {
operations[i].condition_value += 10;
}
usleep(100000); // 100ms延迟
}
// 最终统计
printf("\n7. 最终统计:\n");
printf(" 总操作数: 5\n");
printf(" 完成操作数: %d\n", completed_operations);
printf(" 取消操作数: %d\n", cancelled_operations);
printf(" 进行中操作数: %d\n", 5 - completed_operations - cancelled_operations);
// 显示每个操作的最终状态
printf("\n8. 操作状态详情:\n");
for (int i = 0; i < 5; i++) {
operation_context_t *op_ctx = &operations[i];
printf(" 操作 %d: ", i + 1);
if (op_ctx->is_cancelled) {
printf("已取消 ");
} else if (op_ctx->is_completed) {
printf("已完成 ");
} else {
printf("进行中 ");
}
switch (op_ctx->strategy) {
case CANCEL_STRATEGY_IMMEDIATE:
printf("(立即取消策略)");
break;
case CANCEL_STRATEGY_TIMEOUT:
printf("(超时取消策略)");
break;
case CANCEL_STRATEGY_CONDITIONAL:
printf("(条件取消策略)");
break;
case CANCEL_STRATEGY_NEVER:
printf("(从不取消策略)");
break;
}
printf("\n");
}
// 清理资源
cleanup:
printf("\n9. 清理资源:\n");
// 释放缓冲区
for (int i = 0; i < 5; i++) {
if (operations[i].iocb.aio_buf) {
free((void*)(uintptr_t)operations[i].iocb.aio_buf);
}
}
close(fd);
unlink(filename);
io_destroy(ctx);
printf(" ✓ 资源清理完成\n");
return 0;
}
int main() {
return demo_conditional_cancel_strategy();
}
示例5:错误处理和恢复
c
#include <linux/aio_abi.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
/**
* 系统调用包装函数
*/
static inline int io_setup(unsigned nr_events, aio_context_t *ctxp) {
return syscall(__NR_io_setup, nr_events, ctxp);
}
static inline int io_destroy(aio_context_t ctx) {
return syscall(__NR_io_destroy, ctx);
}
static inline int io_submit(aio_context_t ctx, long nr, struct iocb **iocbpp) {
return syscall(__NR_io_submit, ctx, nr, iocbpp);
}
static inline int io_cancel(aio_context_t ctx, struct iocb *iocb, struct io_event *result) {
return syscall(__NR_io_cancel, ctx, iocb, result);
}
static inline int io_getevents(aio_context_t ctx, long min_nr, long nr,
struct io_event *events, struct timespec *timeout) {
return syscall(__NR_io_getevents, ctx, min_nr, nr, events, timeout);
}
/**
* 错误处理上下文
*/
typedef struct {
int error_code;
const char *error_message;
int retry_count;
int max_retries;
time_t error_time;
const char *operation_name;
} error_context_t;
/**
* 记录错误信息
*/
void record_error(error_context_t *ctx, int error_code, const char *operation, const char *message) {
ctx->error_code = error_code;
ctx->error_message = message;
ctx->error_time = time(NULL);
ctx->operation_name = operation;
ctx->retry_count++;
printf("错误记录: %s\n", operation);
printf(" 错误码: %d\n", error_code);
printf(" 错误信息: %s\n", message);
printf(" 重试次数: %d/%d\n", ctx->retry_count, ctx->max_retries);
}
/**
* 错误恢复策略
*/
int apply_recovery_strategy(error_context_t *ctx, aio_context_t aio_ctx, struct iocb *iocb) {
printf("应用错误恢复策略:\n");
switch (ctx->error_code) {
case -EAGAIN:
printf(" EAGAIN错误,操作稍后重试\n");
if (ctx->retry_count < ctx->max_retries) {
printf(" 重试操作...\n");
struct iocb *iocbs[1] = {iocb};
int ret = io_submit(aio_ctx, 1, iocbs);
if (ret == 1) {
printf(" ✓ 重试成功\n");
return 0;
} else {
printf(" ✗ 重试失败: %s\n", strerror(-ret));
record_error(ctx, ret, ctx->operation_name, "重试失败");
}
}
break;
case -ECANCELED:
printf(" ECANCELED错误,操作已被取消\n");
printf(" 尝试重新提交操作...\n");
struct iocb *iocbs[1] = {iocb};
int ret = io_submit(aio_ctx, 1, iocbs);
if (ret == 1) {
printf(" ✓ 重新提交成功\n");
return 0;
} else {
printf(" ✗ 重新提交失败: %s\n", strerror(-ret));
record_error(ctx, ret, ctx->operation_name, "重新提交失败");
}
break;
case -EBADF:
printf(" EBADF错误,文件描述符无效\n");
printf(" 建议:检查文件描述符有效性\n");
break;
case -EINVAL:
printf(" EINVAL错误,参数无效\n");
printf(" 建议:检查参数设置\n");
break;
default:
printf(" 未知错误: %s\n", strerror(-ctx->error_code));
printf(" 建议:记录错误并采取适当措施\n");
break;
}
return -1;
}
/**
* 演示错误处理和恢复
*/
int demo_error_handling_recovery() {
aio_context_t ctx;
struct iocb iocb;
struct io_event result;
int fd;
int ret;
error_context_t error_ctx = {0};
printf("=== 错误处理和恢复演示 ===\n");
// 设置错误处理上下文
error_ctx.max_retries = 3;
error_ctx.retry_count = 0;
// 初始化AIO上下文
printf("1. 初始化AIO上下文:\n");
ctx = 0;
ret = io_setup(32, &ctx);
if (ret < 0) {
record_error(&error_ctx, ret, "io_setup", "初始化AIO上下文失败");
apply_recovery_strategy(&error_ctx, ctx, NULL);
return -1;
}
printf(" ✓ AIO上下文初始化成功\n");
// 创建测试文件
printf("\n2. 创建测试文件:\n");
const char *filename = "error_recovery_test.txt";
fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644);
if (fd == -1) {
record_error(&error_ctx, -errno, "open", "创建测试文件失败");
io_destroy(ctx);
return -1;
}
printf(" ✓ 测试文件创建成功\n");
// 准备异步写入操作
printf("\n3. 准备异步写入操作:\n");
const char *test_data = "Error handling and recovery test data.\n";
size_t data_size = strlen(test_data);
memset(&iocb, 0, sizeof(iocb));
iocb.aio_data = 1001;
iocb.aio_lio_opcode = IOCB_CMD_PWRITE;
iocb.aio_fildes = fd;
iocb.aio_buf = (uint64_t)(uintptr_t)test_data;
iocb.aio_nbytes = data_size;
iocb.aio_offset = 0;
printf(" 准备写入操作:\n");
printf(" 数据大小: %zu 字节\n", data_size);
printf(" 用户数据: %llu\n", (unsigned long long)iocb.aio_data);
// 提交异步操作
printf("\n4. 提交异步操作:\n");
struct iocb *iocbs[1] = {&iocb};
ret = io_submit(ctx, 1, iocbs);
if (ret != 1) {
record_error(&error_ctx, ret, "io_submit", "提交异步操作失败");
if (apply_recovery_strategy(&error_ctx, ctx, &iocb) != 0) {
close(fd);
unlink(filename);
io_destroy(ctx);
return -1;
}
}
printf(" ✓ 异步操作提交成功\n");
// 演示各种错误场景
printf("\n5. 演示错误场景:\n");
// 场景1: 尝试取消已完成的操作
printf(" 场景1: 尝试取消已完成的操作\n");
struct io_event events[1];
struct timespec timeout = {2, 0}; // 2秒超时
ret = io_getevents(ctx, 1, 1, events, &timeout);
if (ret > 0) {
printf(" 操作已完成,尝试取消...\n");
ret = io_cancel(ctx, &iocb, &result);
if (ret == -EAGAIN) {
printf(" ✓ 取消失败:操作已完成 (EAGAIN)\n");
} else if (ret == 0) {
printf(" ✓ 操作取消成功\n");
} else {
printf(" 取消操作返回: %s\n", strerror(-ret));
}
}
// 场景2: 使用无效的iocb尝试取消
printf("\n 场景2: 使用无效的iocb尝试取消\n");
struct iocb invalid_iocb;
memset(&invalid_iocb, 0, sizeof(invalid_iocb));
invalid_iocb.aio_data = 9999;
ret = io_cancel(ctx, &invalid_iocb, &result);
if (ret == -EAGAIN) {
printf(" ✓ 取消失败:无效操作 (EAGAIN)\n");
} else {
printf(" 取消操作返回: %s\n", strerror(-ret));
}
// 场景3: 使用无效的上下文ID
printf("\n 场景3: 使用无效的上下文ID\n");
struct iocb test_iocb;
memset(&test_iocb, 0, sizeof(test_iocb));
aio_context_t invalid_ctx = (aio_context_t)-1;
ret = io_cancel(invalid_ctx, &test_iocb, &result);
if (ret == -EINVAL) {
printf(" ✓ 操作失败:无效上下文ID (EINVAL)\n");
} else {
printf(" 取消操作返回: %s\n", strerror(-ret));
}
// 场景4: 重复取消同一个操作
printf("\n 场景4: 重复取消操作\n");
ret = io_cancel(ctx, &iocb, &result);
if (ret == -EAGAIN) {
printf(" ✓ 第二次取消失败:操作已处理 (EAGAIN)\n");
} else if (ret == 0) {
printf(" ✓ 第二次取消成功\n");
ret = io_cancel(ctx, &iocb, &result);
if (ret == -EAGAIN) {
printf(" ✓ 第三次取消失败:操作已处理 (EAGAIN)\n");
}
} else {
printf(" 第二次取消操作返回: %s\n", strerror(-ret));
}
// 演示资源清理错误处理
printf("\n6. 演示资源清理错误处理:\n");
// 正常关闭文件
printf(" 正常关闭文件:\n");
if (close(fd) == 0) {
printf(" ✓ 文件关闭成功\n");
} else {
record_error(&error_ctx, -errno, "close", "关闭文件失败");
printf(" 尝试强制清理...\n");
}
// 删除测试文件
printf(" 删除测试文件:\n");
if (unlink(filename) == 0) {
printf(" ✓ 测试文件删除成功\n");
} else {
record_error(&error_ctx, -errno, "unlink", "删除测试文件失败");
printf(" 注意:可能需要手动清理测试文件\n");
}
// 销毁AIO上下文
printf(" 销毁AIO上下文:\n");
ret = io_destroy(ctx);
if (ret == 0) {
printf(" ✓ AIO上下文销毁成功\n");
} else {
record_error(&error_ctx, ret, "io_destroy", "销毁AIO上下文失败");
printf(" 销毁操作返回: %s\n", strerror(-ret));
}
// 显示错误处理总结
printf("\n=== 错误处理总结 ===\n");
printf("1. 常见错误类型:\n");
printf(" ✓ EAGAIN: 操作无法取消(已完成或不存在)\n");
printf(" ✓ EINVAL: 参数无效\n");
printf(" ✓ EBADF: 文件描述符无效\n");
printf(" ✓ ECANCELED: 操作已被取消\n");
printf("\n2. 错误处理策略:\n");
printf(" ✓ 记录错误信息\n");
printf(" ✓ 根据错误类型采取不同措施\n");
printf(" ✓ 必要时重试操作\n");
printf(" ✓ 优雅降级处理\n");
printf("\n3. 恢复策略:\n");
printf(" ✓ 重试机制\n");
printf(" ✓ 备用方案\n");
printf(" ✓ 资源清理\n");
printf(" ✓ 状态恢复\n");
printf("\n4. 最佳实践:\n");
printf(" ✓ 完善的错误记录\n");
printf(" ✓ 适当的重试策略\n");
printf(" ✓ 资源泄漏预防\n");
printf(" ✓ 用户友好提示\n");
return 0;
}
int main() {
return demo_error_handling_recovery();
}
io_cancel 使用注意事项
系统要求:
1. 内核版本 : 需要支持AIO的Linux内核
2. 权限要求 : 通常不需要特殊权限
3. 架构支持: 支持所有主流架构
取消限制:
1. 操作状态 : 只能取消排队或正在执行的操作
2. 时间窗口 : 已完成的操作无法取消
3. 资源释放: 取消后需要清理相关资源
错误处理:
1. EAGAIN : 操作无法取消(已完成或不存在)
2. EINVAL : 参数无效
3. EBADF : 文件描述符无效
4. ECANCELED: 操作已被取消
性能考虑:
1. 取消开销 : 取消操作本身也有性能开销
2. 批量处理 : 批量取消可能更高效
3. 超时设置 : 合理设置超时时间
4. 状态检查: 取消前检查操作状态
安全考虑:
1. 参数验证 : 验证所有输入参数
2. 内存管理 : 确保缓冲区内存有效
3. 资源清理 : 及时清理已取消操作的资源
4. 状态同步: 确保多线程环境下的状态一致性
最佳实践:
io_cancel vs 相似函数对比
io_cancel vs io_destroy:
c
// io_cancel: 取消单个操作
io_cancel(ctx, &iocb, &result);
// io_destroy: 销毁整个AIO上下文(取消所有操作)
io_destroy(ctx);
io_cancel vs io_getevents:
c
// io_cancel: 主动取消操作
io_cancel(ctx, &iocb, &result);
// io_getevents: 被动等待操作完成
io_getevents(ctx, 1, 1, events, &timeout);
常见使用场景
1. 超时处理:
c
// 异步操作超时后取消
if (operation_timeout) {
io_cancel(ctx, &iocb, &result);
}
2. 用户中断:
c
// 用户取消操作时取消所有相关异步操作
for (int i = 0; i < operation_count; i++) {
io_cancel(ctx, &iocbs[i], &results[i]);
}
3. 资源清理:
c
// 应用程序退出前取消未完成的操作
io_cancel(ctx, &iocb, &result);
总结
io_cancel
是Linux AIO框架中重要的操作取消函数,提供了:
1. 操作控制 : 精确控制异步操作的生命周期
2. 资源管理 : 及时释放不需要的资源
3. 错误处理 : 完善的错误处理机制
4. 灵活性: 支持多种取消策略
通过合理使用 io_cancel
,可以构建更加健壮和灵活的异步I/O应用。在实际应用中,需要注意错误处理、资源管理和性能优化等关键问题。