io_cancel系统调用及示例

io_cancel 函数详解

1. 函数介绍

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

2. 函数原型

c 复制代码
#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. 相似函数,或关联函数

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. 状态同步: 确保多线程环境下的状态一致性

最佳实践:

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

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应用。在实际应用中,需要注意错误处理、资源管理和性能优化等关键问题。

相关推荐
AOwhisky35 分钟前
云计算一阶段Ⅱ——3. Linux 计划任务管理
linux·chrome·云计算
wdfk_prog1 小时前
实战指南:如何将Git仓库中的特定文件夹及其历史完整迁移到另一个仓库
大数据·linux·运维·笔记·git·学习·elasticsearch
好好先森&1 小时前
C语言:模块化编程
c语言·c++·windows
瑞士龙珠1 小时前
CentOS 7.4 → 7.9.2009 升级操作步骤(使用 Vault 仓库)
linux
重生之我是Java开发战士1 小时前
【C语言】结构体详解
c语言·开发语言
highersister1 小时前
【RK3568源码编译准备工作】
linux
鸠摩智首席音效师2 小时前
如何在 Ubuntu 24.04 安装 KVM ?
linux·运维·ubuntu
静渊谋2 小时前
应急响应整理
linux·windows
CODE_RabbitV3 小时前
Linux 文件与目录操作命令宝典
linux·运维·服务器
gnawkhhkwang3 小时前
io_submit系统调用及示例
linux·c语言