为什么在condition_variable.wait()期间线程一直挂起



我想写一个程序,使用线程。线程应该休眠并等待,直到堆栈的头指针改变,然后做一些事情并再次休眠。然而,我的线程一直挂在wait函数上,我的程序也挂在它上面,等待语句的改变。但它不会,因为整个程序等待线程完成。所以. .这是我的代码,当我将线程join放入析构函数时,它正在工作,但我希望它在push发生之前运行,因此它可以在运行期间注意到变化,然后在int main()完成时安全终止。

#include <iostream>
#include <fstream>
#include <thread>
#include <mutex>
#include <condition_variable>
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;
public:
Stack() {
head = nullptr;
prevHead = nullptr;
outFile.open("C:\Users\mayday\Desktop\stack.txt");
writeThread = std::thread(&Stack::WriteStack, this);
}

~Stack() {
writeThread.join();
}
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 (true) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [this]() { return head != prevHead; });
Node* temp = head;
while (temp != nullptr) {
outFile << temp->data << " ";
temp = temp->next;
}
outFile << std::endl;
outFile.close();
prevHead = head;
lock.unlock();
}
}
};
int main() {
Stack s;
s.Push(1);
s.Push(2);
s.Push(3);
return 0;
}

我尝试为线程join()创建新的void方法来从main执行它,但是如果我在Push()之前实现它,那么它将永远睡眠并且什么都不做。即使是对析构函数的调用,它也只是在做一些事情,并一直冻结等待条件改变。当然,我可以在最后检查head == prevHead,然后打破它,但我希望它只是在后台睡眠,直到它会被通知的变化。我该如何克服这种僵局呢?对不起,我的英语不好。

几点:

正如我所说的注释,没有理由显式地调用lock.unlock(),因为unique_lock的析构函数会为您做这件事。

同样,我倾向于notify_all()而不是notify_one(),这样我就不必考虑可能产生的额外边缘情况。

但是以上两个问题都不是你挂起的原因。

你的代码挂起了,因为没有什么可以让线程退出的信号。主线程只是挂起对堆栈析构函数中writeThread.join()的调用,等待工作线程退出。而你的工作线程只是挂在外面等待再次通知。

为你的类添加一个新的bool成员needToExit,在构造函数中初始化为false

在析构函数中,将该变量设置为true(在互斥锁下),然后通知cv。

在你的线程中,检查这个变量作为退出条件。

. 根据您的评论,我还添加了对Push的更改,以便它将等待工作线程完成处理先前的头指针更改。cv.notify_all调用是在线程完成每次头部变化的处理时,向主线程发送信号。

class Stack {
private:
Node* head;
std::mutex mtx;
std::thread writeThread;
std::ofstream outFile;
Node* prevHead;
std::condition_variable cv;
bool needToExit;   // DECLARE THIS
public:
Stack() {
head = nullptr;
prevHead = nullptr;
needToExit = false;   // INIT TO FALSE
outFile.open("C:\Users\jselbie\Desktop\stack.txt");
writeThread = std::thread(&Stack::WriteStack, this);
}

~Stack() {
{
std::unique_lock<std::mutex> lock(mtx);
needToExit = true;  // SET UNDER LOCK IN DESTRUCTOR
}
cv.notify_all(); // signal cv to wake up thread to check condition
writeThread.join();
}

void Push(int data) {
std::cout << "push(" << data << ")n";
// wait for any previous head change to
// be picked up and processed by the thread
cv.wait(lock, [this]() { 
return (head == prevHead)
});
std::unique_lock<std::mutex> lock(mtx);
Node* newNode = new Node();
newNode->data = data;
newNode->next = head;
head = newNode;
cv.notify_all();
}
void WriteStack() {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [this]() { 
// CHECK needToExit in addition to pointer change
return ((head != prevHead) || needToExit); 
});
if (head != prevHead) {
Node* temp = head;
while (temp != nullptr) {
outFile << temp->data << " ";
temp = temp->next;
}
outFile << std::endl;
outFile.close();
prevHead = head;
cv.notify_all(); // notify main thread
}
if (needToExit)
break; // EXIT THREAD WHEN needtoExit==true
}
}
}
};

最新更新