4. 创建完成队列
任务目标
在RDMA编程中,完成队列(Completion Queue, CQ)用于存放异步操作(如发送、接收、读写)的完成通知。本案例创建CQ并设置队列长度,随后查询其属性以验证创建结果。
环境与依赖
需要Linux系统、RDMA网卡(或Soft-RoCE模拟设备)、librdmacm和libibverbs开发库。编译时链接-libverbs。
关键完整代码
#include <infiniband/verbs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
struct ibv_device **dev_list;
struct ibv_context *ctx = NULL;
struct ibv_pd *pd = NULL;
struct ibv_cq *cq = NULL;
struct ibv_cq_attr cq_attr;
struct ibv_device_attr dev_attr;
int num_devices, cqe = 256; /* 请求的CQ深度 */
/* 1. 获取设备列表 */
dev_list = ibv_get_device_list(&num_devices);
if (!dev_list || num_devices < 1) {
fprintf(stderr, "未找到RDMA设备\n");
return 1;
}
/* 2. 打开第一个可用设备 */
ctx = ibv_open_device(dev_list[0]);
if (!ctx) {
fprintf(stderr, "打开设备失败\n");
goto cleanup_dev_list;
}
/* 3. 查询设备属性,确认最大CQ容量 */
if (ibv_query_device(ctx, &dev_attr)) {
fprintf(stderr, "查询设备属性失败\n");
goto cleanup_ctx;
}
printf("设备支持最大CQ深度: %u\n", dev_attr.max_cqe);
/* 4. 分配保护域(CQ不强制需要PD,但后续关联QP时必需) */
pd = ibv_alloc_pd(ctx);
if (!pd) {
fprintf(stderr, "分配PD失败\n");
goto cleanup_ctx;
}
/* 5. 创建CQ */
cq = ibv_create_cq(ctx, cqe, NULL, NULL, 0);
if (!cq) {
fprintf(stderr, "创建CQ失败\n");
goto cleanup_pd;
}
printf("CQ创建成功,请求深度=%d\n", cqe);
/* 6. 查询CQ属性验证 */
memset(&cq_attr, 0, sizeof(cq_attr));
if (ibv_query_cq(cq, &cq_attr)) {
fprintf(stderr, "查询CQ属性失败\n");
goto cleanup_cq;
}
printf("CQ实际深度: %d\n", cq_attr.cqe);
/* 7. 清理资源 */
ibv_destroy_cq(cq);
ibv_dealloc_pd(pd);
ibv_close_device(ctx);
ibv_free_device_list(dev_list);
return 0;
cleanup_cq:
ibv_destroy_cq(cq);
cleanup_pd:
ibv_dealloc_pd(pd);
cleanup_ctx:
ibv_close_device(ctx);
cleanup_dev_list:
ibv_free_device_list(dev_list);
return 1;
}
编译与运行
gcc -o create_cq create_cq.c -libverbs
./create_cq
验证方法与判定标准
程序执行后应依次输出:
- 设备支持的最大CQ深度(数值取决于硬件,通常≥65536)
CQ创建成功,请求深度=256CQ实际深度: 256(或设备允许的最近值)
若最后一行输出的实际深度与请求深度一致(或为设备支持的最大值向下取整),且程序退出码为0,则判定CQ创建与查询功能正常。若输出创建CQ失败,请检查设备是否支持RDMA、权限是否足够(可能需要sudo),或尝试减小cqe值(如64)后重试。
常见问题
- ibv_open_device返回NULL:确认
ibv_get_device_list返回的设备可用,且当前用户有访问权限。 - 创建CQ返回NULL:请求的
cqe超过设备max_cqe,或内存不足。可先查询设备属性后设置合理值。 - 实际深度与请求不同:部分硬件会向上取整到2的幂次或受限于
max_cqe,属正常现象,只要实际值≥请求值即可。