繁体   English   中英

如何可靠地结束被 IO 任务阻塞的线程

[英]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 提供了pollepoll ,它们允许您等待文件描述符上的输入并等待同一函数调用中的事件对象(实际上,Linux 将事件对象也视为文件描述符)。 Microsoft Windows 提供与WaitForMultipleObjects类似的功能。

您可以创建一个事件对象(在 Linux 上使用eventfd ,在 Windows 上使用CreateEvent )并将此事件对象设置为在您希望线程取消等待并退出时发出信号。 如果线程正在等待事件对象变为信号或文件描述符上的新输入,那么一旦事件变为信号,它就会停止等待。 这样,在等待文件描述符上的新输入时,您将不再遇到线程阻塞的问题。

如果您想实现此解决方案并继续使用std::istream进行输入,那么您可能需要考虑派生自己的std::streambuf类,该类实现成员函数underflow ,使其首先调用平台之一 -特定函数poll / epoll / WaitForMultipleObjects等待新输入变为可用或退出事件发出信号。 如果发出退出事件信号,则函数underflow应返回Traits::eof() ,这将导致设置std::istreameofbit并立即返回std::getline 否则,一旦报告有新输入可用,您就可以调用特定于平台的函数之一read / ReadFile来填充std::streambuf对象的获取区域,并根据需要调整对象的指针。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM