I have a class which executes a thread in order to constantly read lines from a given istream, which are then parsed internally. At some point I want it to end, but since the getline()
call is blocking, it may wait forever on 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...
If std::getline
encounters end-of-file, then it will immediately return and stop blocking. 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.
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). Microsoft Windows offers similar functionality with 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. 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. 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. 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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.