libibverbs:多线程CQ事件轮询——wait_event函数线程安全性问询
RDMA wait_event() 线程安全性分析
问题描述
我使用下方的函数监听RDMA事件,请问该wait_event()函数是否线程安全?即能否在多线程中并行处理CQ事件?我尤其关注ibv_get_cq_event()在多线程环境下的使用安全性。实现代码如下:
ibv_wc RdmaBase::wait_event(bool ignore_errors) { // This is kind of a coroutine instead of polling the events in a different thread ibv_wc ret{}; start: if(!m_polling) { void* ctxt; HENSURE_ERRNO(ibv_get_cq_event(m_comp_channel, &m_cq, &ctxt) == 0); ibv_ack_cq_events(m_cq, 1); HENSURE_ERRNO(ibv_req_notify_cq(m_cq, 0) == 0); m_polling = true; } while(true) { const int num_completions = ibv_poll_cq(m_cq, 1, &ret); HENSURE_ERRNO(num_completions >= 0); if(num_completions == 0) { m_polling = false; goto start; } else { if(!ignore_errors && ret.status != IBV_WC_SUCCESS) { FATAL_ERROR("Failed status %s (%d) for wr_id %d\n", ibv_wc_status_str(ret.status), ret.status, (int) ret.wr_id); } break; } } return ret; }
核心结论
这个wait_event()不是线程安全的,不能直接在多线程环境下并行调用,风险点主要集中在共享变量的无保护访问和逻辑竞态上。
1. ibv_get_cq_event()本身的线程安全性
RDMA verbs规范明确:ibv_comp_channel是线程安全的——多个线程可以同时调用ibv_get_cq_event()在同一个通道上等待事件,内部数据结构不会损坏,且每个事件只会被一个线程唤醒接收,不会重复分发。但你的代码中后续的共享变量操作才是核心风险。
2. 共享变量m_polling的竞态问题
m_polling作为类成员变量,被多个线程同时读写却没有任何同步机制(如互斥锁、原子变量):
- 当线程A通过
if(!m_polling)判断进入分支,但还未将m_polling设为true时,线程B可能也通过同一判断,导致多个线程同时执行ibv_get_cq_event()、ibv_ack_cq_events()和ibv_req_notify_cq()。 - 这种竞态会引发重复ACK事件、重复注册CQ通知,甚至多个线程同时处理同一CQ的混乱逻辑。
3. ibv_poll_cq()的线程安全说明
ibv_poll_cq()本身是线程安全的——多个线程可以同时对同一CQ调用poll操作,每个完成队列条目(WC)只会被一个线程获取。但结合你的代码逻辑,因m_polling的竞态,会导致多线程同时进入poll循环,虽不会破坏CQ内部结构,但会出现重复处理或逻辑冲突问题。
修复建议
- 给
m_polling的读写加互斥锁(如std::mutex),确保同一时间只有一个线程能进入事件获取和通知注册分支。 - 若要实现多线程并行处理CQ事件,更合理的方案是:单线程专门负责
ibv_get_cq_event()和通知注册,将poll到的WC分发给多个工作线程处理;或者为每个线程分配独立的CQ和completion channel。
内容的提问来源于stack exchange,提问作者rafoo
相关产品推荐
相关产品推荐

