c++ - 如何可靠地结束在 IO 任务上阻塞的线程
问题描述
我有一个执行线程的类,以便不断地从给定的 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
.
您可以创建一个事件对象(eventfd
在 Linux、CreateEvent
Windows 上使用)并在您希望线程取消等待并退出时将此事件对象设置为发出信号。如果线程正在等待事件对象发出信号或文件描述符上的新输入,那么一旦事件发出信号,它将停止等待。这样,在等待文件描述符的新输入时,您将不再遇到线程阻塞的问题。
如果您想实现此解决方案并继续使用std::istream
输入,那么您可能需要考虑派生您自己的类,std::streambuf
该类实现成员函数underflow
的方式是它首先调用平台特定函数之一poll
//等待新的输入变为可用或退出事件发出信号。如果退出事件发出信号,那么函数应该返回,这将导致in被设置并立即返回。否则,一旦报告新输入可用,您可以调用平台特定函数之一/来填充对象的获取区域,并根据需要调整对象的指针。epoll
WaitForMultipleObjects
underflow
Traits::eof()
eofbit
std::istream
std::getline
read
ReadFile
std::streambuf
推荐阅读
- sql-server - 如何创建具有快照隔离级别的 Flyway 模式历史记录?
- ada - GNAT.Command_Line.Getopt - 如何强制所有命令行选项都有效?
- c# - 带有 LiveCharts 的 WPF 在运行时添加带有 DataBinding 的系列
- reactjs - React + TypeScript 中的 setState:FormData 不是“Blob”类型
- python - Dockerfile 未安装最新的 pypi 版本
- typo3 - 将设置传递给 FLUIDTEMPLATE
- python - 当 oneTimeSetup 方法具有固定范围 =“会话”时出现错误
- angular - Angular - 对多个路径使用相同的模块
- authorization - Azure 数据工厂 - 在不同资源组上共享集成运行时
- database - 使用 DBMS_DATAPUMP api 从不同的模式导出表