#c
Вопрос:
У меня есть класс, который выполняет поток для постоянного чтения строк из данного потока, которые затем анализируются внутри. В какой-то момент я хочу, чтобы это закончилось, но так getline()
как вызов блокируется, он может ждать вечно join()
.
#pragma once
#include <thread>
#include <iostream>
class Parser {
private:
std::istreamamp; input;
std::thread parserThread;
public:
Parser(std::istreamamp; input_) : input(input_)/* ... */{}
~Parser() {
stop();
}
void start() {
// Avoid multiple threads...
parserThread = std::thread(amp;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) amp;amp; continueParsing) {
//...
}
}
};
Существует ли какой-либо стандартный способ сделать это? Или мой подход (чтобы поток читался вечно) неверен? Если бы это был C, я бы просто убил нить…
Комментарии:
1. Ничего, о чем я знаю в стандартном C . Возможно, вы захотите оформить заказ на повышение. Асио . Уничтожение потока на большинстве платформ приведет к неопределенному поведению.
2. Моя непосредственная мысль заключается в том, почему вы вытаскиваете ковер из-под процесса, который передает вам данные? Может ли быть никакого сотрудничества между этими двумя?
3. @Galik Это довольно большое приложение на Python, которое постоянно выводит строки json с маркерами распознавания голоса, поэтому я подумал о том, чтобы просто передать его вывод в свою программу на C .
4. Убийство потока обычно является ужасной идеей на любом языке; возможно, позже вы не сможете закрыть поток, например, из которого поток читал.
5. Может быть, использовать что-то, что обрабатывает символ за символом и добавляет к
buffer
? Если установлен флаг отменено, то немедленно выйдите из цикла. Кроме того, ваш код небезопасен для потоков.. Вам нужно использоватьatomic
,mutex
, иcondition_variable
, чтобы подать потоку сигнал о том, что он должен прекратить обработку, а затем присоединиться к нему. Еще одна проблема-звонитьstart
дважды.. деструктор вашего предыдущего потока будет вызван, и он выдаст исключение, так как он не присоединен или отсоединен.
Ответ №1:
Если std::getline
обнаружится конец файла, то он немедленно вернется и прекратит блокировку. Поэтому, если бы вы могли каким-то образом организовать, чтобы это произошло, когда вы хотите, чтобы поток вышел, то это, вероятно, было бы лучшим решением. Однако, если это невозможно, то я боюсь, что ISO C сам по себе не предлагает никакого способа решения проблемы.
Но большинство платформ предлагают расширения для конкретной платформы, которые позволяют одновременно обслуживать более одного объекта ядра. Например, Linux предлагает poll
и epoll
который позволяет вам ждать ввода в файловый дескриптор и ждать объекта события в одном и том же вызове функции (на самом деле Linux рассматривает объекты событий также как файловые дескрипторы). Microsoft Windows предлагает аналогичную функциональность с WaitForMultipleObjects
.
Вы можете создать объект события (используя eventfd
в Linux, CreateEvent
в Windows) и установить для этого объекта события сигнал, когда вы хотите, чтобы ваш поток отменил ожидание и вышел. Если поток ожидает либо сигнала объекта события, либо нового ввода в файловый дескриптор, то он прекратит ожидание, как только событие станет сигнализированным. Таким образом, у вас больше не будет проблемы с блокировкой потока во время ожидания новых входных данных в файловом дескрипторе.
Если вы хотите реализовать это решение и продолжить использовать std::istream
его для ввода, то вам может потребоваться рассмотреть возможность создания собственного std::streambuf
класса, который реализует функцию-член underflow
таким образом, чтобы он сначала вызывал одну из функций, специфичных для платформы poll
/ epoll
/ WaitForMultipleObjects
, чтобы дождаться либо появления новых входных данных, либо сигнала о завершении события. Если сигнализируется событие quit, то функция underflow
должна вернуться Traits::eof()
, что приведет eofbit
std::istream
к установке и std::getline
немедленному возвращению in. В противном случае, как только появится сообщение о наличии новых входных данных, вы можете вызвать одну из функций, специфичных для платформы read
/ ReadFile
чтобы заполнить область получения std::streambuf
объекта, при необходимости отрегулируйте указатели объекта.
Комментарии:
1. Большое спасибо! Просто чтобы добавить для дальнейшего использования, я также нашел действительно более уродливое решение, сделав неблокирующее
std::getline
со статическими буферами иreadsome
. Я тоже это проверю, это звучит как идеальная летняя тренировка!