C++如何中断等待std::condition_variable_any的线程及代码疑问
《C++ Concurrency in Action》可中断线程实现疑问解答
问题1解答
Lockable& lk是你用来保护条件变量关联共享数据的锁,核心作用有两个:- 匹配
std::condition_variable_any的接口要求:条件变量的wait方法进入阻塞时会调用锁的unlock释放锁,被唤醒时会调用lock重新持有锁。custom_lock需要持有这个锁的引用,才能将用户锁的持有/释放逻辑和内部set_clear_mutex的操作绑定,保证中断逻辑的线程安全。 - 维持条件变量的标准使用范式:调用
wait前必须持有保护共享数据的锁,才能避免检查等待条件和进入wait之间出现竞争漏洞。
- 匹配
- 要求传入时
lk已经加锁的原因:- 符合条件变量的基础使用规范:C++标准明确要求调用条件变量的
wait方法前必须持有对应锁,否则属于未定义行为。你在调用interruptible_wait之前,必然已经用这个锁访问了共享数据,判断需要进入等待,如果在custom_lock内部才加锁,检查等待条件和加锁之间会出现时间窗口,其他线程修改共享数据会直接导致逻辑错误。 - 规避死锁风险:custom_lock构造时已经先加了内部的
set_clear_mutex,如果此时再加用户的lk,锁顺序就变成set_clear_mutex→lk,而其他操作共享数据的线程如果先加lk再加set_clear_mutex,就会出现死锁。保持传入时lk已经加锁,固定了锁顺序为lk→set_clear_mutex,从根源上避免了死锁。
- 符合条件变量的基础使用规范:C++标准明确要求调用条件变量的
问题2解答
你的测试用法在验证中断功能的场景下是完全正确的,代码可以正常运行,调用interrupt后会触发thread_interrupted异常,被catch块捕获输出"interrupted"。
如果是生产环境使用,还需要补充条件变量的谓词判断:你当前的用法没有传入等待条件,会存在虚假唤醒问题,也就是wait可能没有被notify也没有被中断就自行返回。实际使用时建议给interruptible_wait补充带谓词的重载,用法示例如下:
// 补充带谓词的interruptible_wait重载 template <typename Lockable, typename Pred> void interruptible_wait(std::condition_variable_any& cv, Lockable& lk, Pred pred) { while(!pred()) { this_thread_interrupt_flag.wait(cv, lk); } } // 生产环境使用示例 std::atomic<bool> data_ready = false; void process_task() { std::condition_variable_any cv; std::mutex m; std::unique_lock<std::mutex> lk(m); try { // 只有data_ready为true时才会正常退出等待,避免虚假唤醒 interruptible_wait(cv, lk, []{ return data_ready.load(); }); // 等待完成后处理共享数据 } catch (const thread_interrupted& e) { std::cout << "task interrupted" << std::endl; } }
内容的提问来源于stack exchange,提问作者myoldgrandpa
相关产品推荐
相关产品推荐

