简体   繁体   English

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

[英]How to reliably end a thread blocked on an IO task

I have a class which executes a thread in order to constantly read lines from a given istream, which are then parsed internally.我有一个执行线程的类,以便不断从给定的 istream 中读取行,然后在内部进行解析。 At some point I want it to end, but since the getline() call is blocking, it may wait forever on join() .在某些时候,我希望它结束​​,但由于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) { 
            //...
        }

    }
};

Is there any standard way to accomplish this?有没有标准的方法来实现这一点? Or is my approach (have a thread reading forever) wrong?或者我的方法(永远读一个线程)是错误的? If it were CI would just kill the thread...如果是 CI 只会杀死线程......

If std::getline encounters end-of-file, then it will immediately return and stop blocking.如果std::getline遇到文件尾,那么它将立即返回并停止阻塞。 Therefore, if you could somehow arrange for this to happen when you want the thread to exit, then that would probably be the best solution.因此,如果您能以某种方式安排在您希望线程退出时发生这种情况,那么这可能是最好的解决方案。 However, if that is not possible, then I'm afraid that ISO C++ itself does not offer any way to solve the problem.但是,如果这是不可能的,那么恐怕 ISO C++ 本身并没有提供任何解决问题的方法。

But most platforms offer platform-specific extensions which allow you to wait on more than one kernel object at once.但是大多数平台都提供特定于平台的扩展,允许您一次等待多个内核对象。 For example, Linux offers poll and epoll which allows you to wait for input on a file descriptor and to wait for an event object in the same function call (actually, Linux considers event objects also to be file descriptors).例如,Linux 提供了pollepoll ,它们允许您等待文件描述符上的输入并等待同一函数调用中的事件对象(实际上,Linux 将事件对象也视为文件描述符)。 Microsoft Windows offers similar functionality with WaitForMultipleObjects . Microsoft Windows 提供与WaitForMultipleObjects类似的功能。

You could create an event object (using eventfd on Linux, CreateEvent on Windows) and set this event object to signalled when you want your thread to cancel the wait and to quit.您可以创建一个事件对象(在 Linux 上使用eventfd ,在 Windows 上使用CreateEvent )并将此事件对象设置为在您希望线程取消等待并退出时发出信号。 If the thread is waiting for either the event object to become signalled or for new input on the file descriptor, then it will stop waiting as soon as the event becomes signalled.如果线程正在等待事件对象变为信号或文件描述符上的新输入,那么一旦事件变为信号,它就会停止等待。 That way, you will no longer have the problem of the thread blocking while waiting for new input on the file descriptor.这样,在等待文件描述符上的新输入时,您将不再遇到线程阻塞的问题。

If you want to implement this solution and continue using std::istream for input, then you may want to consider deriving your own std::streambuf class which implements the member function underflow in such a way that it first calls one of the platform-specific functions poll / epoll / WaitForMultipleObjects to wait for either new input to become available or for the quit event to become signalled.如果您想实现此解决方案并继续使用std::istream进行输入,那么您可能需要考虑派生自己的std::streambuf类,该类实现成员函数underflow ,使其首先调用平台之一 -特定函数poll / epoll / WaitForMultipleObjects等待新输入变为可用或退出事件发出信号。 If the quit event is signalled, then the function underflow should return Traits::eof() , which will cause the eofbit in std::istream to be set and std::getline to return immediately.如果发出退出事件信号,则函数underflow应返回Traits::eof() ,这将导致设置std::istreameofbit并立即返回std::getline Otherwise, as soon as new input is reported to be available, you can call one of the platform-specific functions read / ReadFile to fill the get area of the std::streambuf object, adjusting the pointers of the object as necessary.否则,一旦报告有新输入可用,您就可以调用特定于平台的函数之一read / ReadFile来填充std::streambuf对象的获取区域,并根据需要调整对象的指针。

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

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