线程在condition_variable.wait()处持续挂起的问题解决咨询
解决多线程Stack监控线程冻结与安全终止问题
核心问题分析
你的代码存在几个关键问题导致线程冻结和程序异常:
- 文件流提前关闭:
WriteStack循环内每次写完就调用outFile.close(),第一次执行后文件流就处于失效状态,后续触发的写入操作完全无效,同时这个操作毫无必要——文件流应该在析构时统一关闭。 - 无线程退出信号:线程在
while(true)中无限等待条件变量,main结束时析构函数调用join(),但线程永远卡在cv.wait()无法退出,导致程序冻结。 - 路径转义错误:原代码中的文件路径
"C:\Users\mayday\Desktop\stack.txt"里的反斜杠未转义,会被编译器解析为无效转义字符(比如\U),必须改为双反斜杠或者正斜杠。 - 条件变量等待逻辑缺失退出判断:仅判断
head != prevHead,线程无法感知程序终止信号,必须结合退出标志调整谓词。
修改后的代码
#include <iostream> #include <fstream> #include <thread> #include <mutex> #include <condition_variable> #include <atomic> struct Node { int data; Node* next; }; class Stack { private: Node* head; std::mutex mtx; std::thread writeThread; std::ofstream outFile; Node* prevHead; std::condition_variable cv; std::atomic<bool> stopFlag; // 线程退出标志 public: Stack() : head(nullptr), prevHead(nullptr), stopFlag(false) { // 修复路径转义问题 outFile.open("C:\\Users\\mayday\\Desktop\\stack.txt"); writeThread = std::thread(&Stack::WriteStack, this); } ~Stack() { // 设置退出标志并通知线程 stopFlag = true; cv.notify_one(); // 等待线程退出 if (writeThread.joinable()) { writeThread.join(); } // 统一关闭文件流 if (outFile.is_open()) { outFile.close(); } // 额外:释放Stack的节点内存,避免内存泄漏 Node* temp = head; while (temp != nullptr) { Node* next = temp->next; delete temp; temp = next; } } void Push(int data) { std::unique_lock<std::mutex> lock(mtx); Node* newNode = new Node(); newNode->data = data; newNode->next = head; head = newNode; lock.unlock(); cv.notify_one(); } void WriteStack() { while (!stopFlag) { // 以退出标志作为循环条件 std::unique_lock<std::mutex> lock(mtx); // 等待:要么收到退出信号,要么head发生变化 cv.wait(lock, [this]() { return stopFlag || head != prevHead; }); if (stopFlag) { break; // 收到退出信号,直接退出循环 } // 写入文件逻辑 Node* temp = head; while (temp != nullptr) { outFile << temp->data << " "; temp = temp->next; } outFile << std::endl; prevHead = head; } } }; int main() { Stack s; s.Push(1); s.Push(2); s.Push(3); return 0; }
关键修改说明
- 添加
stopFlag原子变量:用原子变量保证线程间的可见性,析构时设置为true并通知线程,让线程能跳出循环。 - 调整条件变量谓词:
wait的判断逻辑同时包含退出标志和head变化,线程既能响应Stack更新,也能及时收到终止信号。 - 文件流管理优化:把
outFile.close()移到析构函数,避免提前关闭导致后续写入失效。 - 修复路径转义:将路径中的反斜杠改为双反斜杠,确保文件能正常打开。
- 内存泄漏修复:析构时释放Stack的所有节点内存,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Space Time
相关产品推荐
相关产品推荐

