Condition Variable Wait阻塞Thread Join,线程安全队列挂起问题
问题分析与解决
核心问题
- 队列无数据导致阻塞:你的
ThreadSafeQueue自始至终没有被推入任何数据,wait_and_pop的逻辑就是阻塞等待队列非空——它会释放锁并挂起线程,直到队列有数据且条件谓词!data_.empty()为真才会继续执行。这直接导致第一个线程卡在条件变量的等待步骤,join会一直等待线程完成,程序因此挂起。 - 对条件变量wait方法的误解:
cv.wait()是阻塞式调用,并非非阻塞。它的作用是让线程进入等待状态,直到被其他线程的notify_one()/notify_all()唤醒,且唤醒后会重新检查条件谓词,只有满足条件才会继续执行。 - 未定义行为:你的
main函数中直接使用&ts_que,但根本没有声明ThreadSafeQueue<int> ts_que实例,这属于未定义行为,实际运行中可能引发崩溃或异常。 - 线程串行执行:循环中创建线程后立刻调用
join,会导致线程逐个串行执行,完全失去了多线程并发的意义。
修正后的代码示例
#include <mutex> #include <queue> #include <thread> #include <vector> #include <iostream> template <typename T> class ThreadSafeQueue { private: std::queue<T> data_; mutable std::mutex mut_; std::condition_variable cv_; public: ThreadSafeQueue() {} ThreadSafeQueue(const ThreadSafeQueue& other) { std::lock_guard<std::mutex> lk(other.mut_); data_ = other.data_; } void push(T item) { std::lock_guard<std::mutex> lk(mut_); data_.push(std::move(item)); cv_.notify_one(); } void wait_and_pop(T& item) { std::unique_lock<std::mutex> ulk(mut_); cv_.wait(ulk, [this] { return !data_.empty(); }); item = std::move(data_.front()); data_.pop(); } bool try_pop(T& item) { std::lock_guard<std::mutex> lk(mut_); if (data_.empty()) return false; item = data_.front(); data_.pop(); return true; } bool empty() const { std::lock_guard<std::mutex> lk(mut_); return data_.empty(); } }; int main() { ThreadSafeQueue<int> ts_que; // 初始化队列实例 // 推入数据,让消费线程有数据可处理 ts_que.push(1); ts_que.push(2); ts_que.push(3); std::vector<int> output(3); std::vector<std::thread> threads; // 先创建所有消费线程 for (int i = 0; i < 3; i++) { threads.push_back(std::thread(&ThreadSafeQueue<int>::wait_and_pop, &ts_que, std::ref(output[i]))); } // 统一等待所有线程完成 for (auto& t : threads) { t.join(); } // 验证结果 for (int num : output) { std::cout << num << " "; } std::cout << std::endl; }
关键修正点
- 新增
ThreadSafeQueue<int> ts_que实例,修复未定义行为。 - 在启动消费线程前推入数据,确保
wait_and_pop的条件能被满足,线程不会一直阻塞。 - 将
join移到循环外,让所有线程先启动再统一等待,实现真正的并发执行。
内容的提问来源于stack exchange,提问作者Jiashan Wang
相关产品推荐
相关产品推荐

