C++ TaskRunner使用条件变量后线程卡住无后续日志问题排查
问题根因1:执行任务时仍然持有互斥锁
你在Run函数中,把task_to_run->Run()的调用逻辑放在了std::unique_lock<std::mutex> mlock(m_task_mutex)的作用域内,这意味着执行任务的整个过程中,你都牢牢占着m_task_mutex锁:
- 此时所有调用
PostTask的线程都会阻塞在std::lock_guard<std::mutex> taskGuard(m_task_mutex)这一步,无法投递新任务 - 如果投递的任务内部又调用了
PostTask,会直接触发死锁:任务要等PostTask拿锁,PostTask要等任务执行完释放锁,两边永远卡着
这就是你日志卡在执行任务前的原因:调用task_to_run->Run()之后要么任务本身执行时间很长,要么触发了死锁,所以后面的日志永远打不出来。
修复方案
你只需要把任务从队列里取出来之后,先释放互斥锁,再执行任务逻辑就行,调整后的Run函数逻辑如下:
void TaskRunnerImpl::Run() { while(true) { INFO("{} : {}", __FUNCTION__, 1); Task* task_to_run = nullptr; { std::unique_lock<std::mutex> mlock(m_task_mutex); INFO("{} : Locked Mutex", __FUNCTION__); m_task_cond_var.wait(mlock, [this]() { INFO("{} : Checking Condition", __FUNCTION__); return !(is_running_ && tasks_queue_.empty()); }); INFO("{} : Came out of wait", __FUNCTION__); if(!is_running_) { return; } INFO("{} : Escaped if cond", __FUNCTION__); if(!tasks_queue_.empty()) { INFO("{} : {} : {}", __FUNCTION__, 2, tasks_queue_.size()); // 仅在持有锁阶段完成取任务、出队操作,不执行任务逻辑 task_to_run = tasks_queue_.front(); tasks_queue_.pop_front(); INFO("{} : Popped task, queue size: {}", __FUNCTION__, tasks_queue_.size()); } INFO("{} : Out of lock scope", __FUNCTION__); } // 此处锁自动释放,后续操作不会阻塞其他线程拿锁 // 无锁状态下执行任务、销毁任务 if(task_to_run != nullptr) { task_to_run->Run(); INFO("{} : Task executed, deleting task", __FUNCTION__); delete task_to_run; } INFO("{} : End of iteration", __FUNCTION__); } INFO("{} : returning", __FUNCTION__); }
额外优化建议
你的is_running_变量如果不是原子类型,多线程场景下可能存在可见性问题,建议将其定义为std::atomic<bool>类型,避免编译器优化导致的逻辑异常。
内容的提问来源于stack exchange,提问作者kadina
相关产品推荐
相关产品推荐

