当前位置: 首页 > news >正文

io_cancel系统调用及示例

io_cancel 函数详解

1. 函数介绍

io_cancel 是Linux传统异步I/O (AIO) 系统调用,用于取消先前提交但尚未完成的异步I/O操作。它是AIO框架的重要组成部分,允许应用程序在必要时取消正在进行的异步操作,提供更灵活的I/O控制能力。

2. 函数原型

#include <linux/aio_abi.h>
int io_cancel(aio_context_t ctx_id, struct iocb *iocb, struct io_event *result);

3. 功能

io_cancel 尝试取消指定的异步I/O操作。如果操作仍在排队或尚未开始执行,则可以成功取消;如果操作已经开始执行或已经完成,则取消可能失败。成功取消的操作会返回一个带有ECANCELED错误码的完成事件。

4. 参数

  • aio_context_t ctx_id: AIO上下文ID(由io_setup创建)
  • *struct iocb iocb: 要取消的异步I/O控制块指针
  • *struct io_event result: 用于存储取消结果的事件结构指针

5. 返回值

  • 成功: 返回0
  • 失败: 返回负的错误码

6. 相似函数,或关联函数

  • io_setup: 初始化AIO上下文

  • io_destroy: 销毁AIO上下文

  • io_submit: 提交异步I/O操作

  • io_getevents: 获取完成的异步I/O事件

  • io_pgetevents: 带信号处理的事件获取

7. 示例代码

示例1:基础io_cancel使用

#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);}// 准备新的iocbstruct 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);  // 100msstruct 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:批量操作取消

#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;}// 初始化iocbmemset(&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:超时取消机制

#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;}// 初始化iocbmemset(&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;  // 读取5MBiocb.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:条件取消策略

#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];// 初始化iocbmemset(&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:错误处理和恢复

#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: 使用无效的上下文IDprintf("\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. 状态同步: 确保多线程环境下的状态一致性

最佳实践:

1. 及时取消: 不需要的操作及时取消
2. 状态跟踪: 跟踪每个操作的状态
3. 错误处理: 妥善处理取消失败的情况
4. 资源管理: 确保资源得到正确释放
5. 超时机制: 实现合理的超时取消机制

io_cancel vs 相似函数对比

io_cancel vs io_destroy:

// io_cancel: 取消单个操作
io_cancel(ctx, &iocb, &result);// io_destroy: 销毁整个AIO上下文(取消所有操作)
io_destroy(ctx);

io_cancel vs io_getevents:

// io_cancel: 主动取消操作
io_cancel(ctx, &iocb, &result);// io_getevents: 被动等待操作完成
io_getevents(ctx, 1, 1, events, &timeout);

常见使用场景

1. 超时处理:

// 异步操作超时后取消
if (operation_timeout) {io_cancel(ctx, &iocb, &result);
}

2. 用户中断:

// 用户取消操作时取消所有相关异步操作
for (int i = 0; i < operation_count; i++) {io_cancel(ctx, &iocbs[i], &results[i]);
}

3. 资源清理:

// 应用程序退出前取消未完成的操作
io_cancel(ctx, &iocb, &result);

总结

io_cancel 是Linux AIO框架中重要的操作取消函数,提供了:

1. 操作控制: 精确控制异步操作的生命周期
2. 资源管理: 及时释放不需要的资源
3. 错误处理: 完善的错误处理机制
4. 灵活性: 支持多种取消策略

通过合理使用 io_cancel,可以构建更加健壮和灵活的异步I/O应用。在实际应用中,需要注意错误处理、资源管理和性能优化等关键问题。

http://www.dtcms.com/a/313458.html

相关文章:

  • e2studio开发RA4M2(6)----GPIO外部中断(IRQ)配置
  • 算法题(181):最大直方矩形面积
  • datasets库 的map方法num_proc=16并行踩坑
  • Java 中的 final 关键字有哪些用法?
  • C++ 虚函数相关问题 **
  • 基于云模型的模糊综合风险评估Matlab代码
  • 网关与路由器的区别
  • access系统调用及示例
  • 延迟任务方案-DelayQueue
  • SpringBoot 2.x 升 3.x 避坑指南:企业级项目的实战问题与解决方案
  • Celery-分布式任务队列
  • MySQL深度理解-MySQL锁机制
  • 数据结构学习(day01)
  • 第八章:进入Redis的SET的核心
  • Android系统模块编译调试与Ninja使用指南
  • 【数据分享】各省粮食外贸依存度、粮食波动率等粮食相关数据合集(2011-2022)(获取方式看文末)
  • 【MATLAB】(六)多项式的创建与四则运算
  • python的高校奖助学金系统
  • 23 Active Directory攻击与防护策略解析
  • 编译旧版本的electron内核
  • SpringBoot之整合MyBatisPlus
  • Nvidia Orin DK 刷机CUDA TensorRT+硬盘扩容+ROS+Realsense+OpenCV+Ollama+Yolo11 一站式解决方案
  • 从“配置地狱”到“云端乐园”——Nacos 如何成为分布式微服务配置中心的“定海神针”
  • 数组和指针的关系
  • 操作系统——读者写者问题
  • KNX协议介绍
  • Nvidia Orin + RealSense D435i 与3D地图实现导航
  • Ubuntu系统VScode实现opencv(c++)视频的处理与保存
  • [硬件电路-129]:模拟电路 - 继电器的工作原理、关键指标、常用芯片与管脚定义
  • SpringAI的使用