[英]How to reliably end a thread blocked on an IO task
我有一个执行线程的类,以便不断从给定的 istream 中读取行,然后在内部进行解析。 在某些时候,我希望它结束,但由于getline()
调用被阻塞,它可能会在join()
上永远等待。
#pragma once
#include <thread>
#include <iostream>
class Parser {
private:
std::istream& input;
std::thread parserThread;
public:
Parser(std::istream& input_) : input(input_)/* ... */{}
~Parser() {
stop();
}
void start() {
// Avoid multiple threads...
parserThread = std::thread(&Parser::monitorThread, this);
}
void stop() {
continueParsing = false;
parserThread.join(); // Wait for it to finish
continueParsing = true; // Allow to start another thread at a later point
}
private:
void monitorThread() {
std::string buffer;
// Constantly reads new input until it's told to stop
while(std::getline(input, buffer) && continueParsing) {
//...
}
}
};
有没有标准的方法来实现这一点? 或者我的方法(永远读一个线程)是错误的? 如果是 CI 只会杀死线程......
如果std::getline
遇到文件尾,那么它将立即返回并停止阻塞。 因此,如果您能以某种方式安排在您希望线程退出时发生这种情况,那么这可能是最好的解决方案。 但是,如果这是不可能的,那么恐怕 ISO C++ 本身并没有提供任何解决问题的方法。
但是大多数平台都提供特定于平台的扩展,允许您一次等待多个内核对象。 例如,Linux 提供了poll
和epoll
,它们允许您等待文件描述符上的输入并等待同一函数调用中的事件对象(实际上,Linux 将事件对象也视为文件描述符)。 Microsoft Windows 提供与WaitForMultipleObjects
类似的功能。
您可以创建一个事件对象(在 Linux 上使用eventfd
,在 Windows 上使用CreateEvent
)并将此事件对象设置为在您希望线程取消等待并退出时发出信号。 如果线程正在等待事件对象变为信号或文件描述符上的新输入,那么一旦事件变为信号,它就会停止等待。 这样,在等待文件描述符上的新输入时,您将不再遇到线程阻塞的问题。
如果您想实现此解决方案并继续使用std::istream
进行输入,那么您可能需要考虑派生自己的std::streambuf
类,该类实现成员函数underflow
,使其首先调用平台之一 -特定函数poll
/ epoll
/ WaitForMultipleObjects
等待新输入变为可用或退出事件发出信号。 如果发出退出事件信号,则函数underflow
应返回Traits::eof()
,这将导致设置std::istream
的eofbit
并立即返回std::getline
。 否则,一旦报告有新输入可用,您就可以调用特定于平台的函数之一read
/ ReadFile
来填充std::streambuf
对象的获取区域,并根据需要调整对象的指针。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.