я создал два класса. Один для чтения ввода (через объект istream) и синтаксического анализа, а другой для обработки вывода синтаксического анализатора.
Существует по одному экземпляру каждого из них.
У меня есть синтаксический анализатор, работающий в цикле, вызывающем istream: :get(), а затем создание команд для второго объекта на основе ввода. Затем эти команды помещаются в очередь, которую второй объект обрабатывает в отдельном потоке.
Теперь совершенно очевидно, что мне в конечном итоге нужно иметь возможность отправить команду «Выход». Однако здесь возникает проблема: команда «Выход» также должна завершать цикл синтаксического анализа, но я не могу найти способ сообщить синтаксическому анализатору, что он должен выйти, потому что он перехвачен в istream::get().
Мне нужен способ разбудить его из этого метода, но я не могу его найти...
Я подумал о написании какой-то «последовательности завершения» для объекта istream (в данном случае это cin), создав объект ostream из istream::rdbuf(). Но это не работает - Badbit устанавливается после попытки записи в буфер.
В другом вопросе на StackOverflow я видел упомянутый класс asio библиотеки Boost, но я бы не хотел зависеть от сторонних библиотек. .
Есть ли способ разбудить поток из istream::get() - т.е. есть ли способ записи в буфер istream (возможно, предполагая, что это на самом деле cin) из программы?
Другой подход: быть убить поток, который я также мог бы найти приемлемым, поскольку в этом конкретном месте нет необходимости в очистке. Но как это сделать? (Я полагаюсь на реализацию потока POSIX)
Как освободить поток, заблокированный через istream
Ответы (2)
Вам придется зависеть от чего-то другого, кроме стандартных классов iostream, потому что они не обеспечивают поведение в стиле select()
.
Кроме того, уничтожение потока невозможно с POSIX (и совершенно не работает в Windows). Вы можете отправить запрос на отмену через pthread_cancel()
, но в вашем случае он может застрять в неотменяемом системном вызове. Что особенно интересно для вас, read()
может или не может быть отменено, в зависимости от среды. По крайней мере в одной среде указано, что точка отмены может em> встречаются в read()
, хотя, по общему признанию, это уровень Windows POSIX. Кроме того, Mac OS X, начиная с Leopard 10.5.1 имел неработающую реализацию read()
в отношении возможности отмены.
Преодолев это препятствие, вы также должны рассмотреть непростые отношения между деструкторами C++ и pthread_cancel. Не все среды гарантируют, что будут вызваны деструкторы, поэтому вы должны быть крайне осторожны при использовании pthread_cancel в коде C++.
Короче говоря, для прерываемого ввода-вывода используйте низкоуровневый ввод-вывод и select()
: один fd для ввода-вывода, второй fd (созданный pipe()
) для сигнализации. Или, если вы смелы, используйте AIO, но вы, вероятно, лучше отключите использование интерфейса высокого уровня, такого как Boost.Asio .
Есть ли шанс, что это реализовано в .NET? - если да, взгляните на Reactive Framework. Он обеспечивает очень элегантный способ обработки потоков и особенно отмены их на лету. - Кроме того, вы получаете очень расширяемую библиотеку расширения Linq для всевозможных вещей, таких как буферизация, мемоизация, Zip и т. Д.
Мы часто используем его для преобразования (и анализа), моделирования потоковых данных.
У Джеффа из команды Reative есть несколько хороших блогов о Потоковая и реальная здесь: