Как освободить поток, заблокированный через istream

я создал два класса. Один для чтения ввода (через объект istream) и синтаксического анализа, а другой для обработки вывода синтаксического анализатора.
Существует по одному экземпляру каждого из них.
У меня есть синтаксический анализатор, работающий в цикле, вызывающем istream: :get(), а затем создание команд для второго объекта на основе ввода. Затем эти команды помещаются в очередь, которую второй объект обрабатывает в отдельном потоке.
Теперь совершенно очевидно, что мне в конечном итоге нужно иметь возможность отправить команду «Выход». Однако здесь возникает проблема: команда «Выход» также должна завершать цикл синтаксического анализа, но я не могу найти способ сообщить синтаксическому анализатору, что он должен выйти, потому что он перехвачен в istream::get().
Мне нужен способ разбудить его из этого метода, но я не могу его найти...
Я подумал о написании какой-то «последовательности завершения» для объекта istream (в данном случае это cin), создав объект ostream из istream::rdbuf(). Но это не работает - Badbit устанавливается после попытки записи в буфер.
В другом вопросе на StackOverflow я видел упомянутый класс asio библиотеки Boost, но я бы не хотел зависеть от сторонних библиотек. .
Есть ли способ разбудить поток из istream::get() - т.е. есть ли способ записи в буфер istream (возможно, предполагая, что это на самом деле cin) из программы?
Другой подход: быть убить поток, который я также мог бы найти приемлемым, поскольку в этом конкретном месте нет необходимости в очистке. Но как это сделать? (Я полагаюсь на реализацию потока POSIX)


person iolo    schedule 21.10.2010    source источник


Ответы (2)


Вам придется зависеть от чего-то другого, кроме стандартных классов iostream, потому что они не обеспечивают поведение в стиле select().

Кроме того, уничтожение потока невозможно с POSIX (и совершенно не работает в Windows). Вы можете отправить запрос на отмену через pthread_cancel(), но в вашем случае он может застрять в неотменяемом системном вызове. Что особенно интересно для вас, read() может или не может быть отменено, в зависимости от среды. По крайней мере в одной среде указано, что точка отмены может встречаются в read(), хотя, по общему признанию, это уровень Windows POSIX. Кроме того, Mac OS X, начиная с Leopard 10.5.1 имел неработающую реализацию read() в отношении возможности отмены.

Преодолев это препятствие, вы также должны рассмотреть непростые отношения между деструкторами C++ и pthread_cancel. Не все среды гарантируют, что будут вызваны деструкторы, поэтому вы должны быть крайне осторожны при использовании pthread_cancel в коде C++.

Короче говоря, для прерываемого ввода-вывода используйте низкоуровневый ввод-вывод и select(): один fd для ввода-вывода, второй fd (созданный pipe()) для сигнализации. Или, если вы смелы, используйте AIO, но вы, вероятно, лучше отключите использование интерфейса высокого уровня, такого как Boost.Asio .

person Marcelo Cantos    schedule 22.10.2010
comment
На самом деле я пробовал вызов pthread_cancel(), но, как вы сказали, он вообще не работает или совершенно ненадежен. Однако деструкторы, вероятно, не были бы проблемой, поскольку я мог бы поместить код очистки в другой поток. Спасибо за ссылку на select(). Я не знал этого. - person iolo; 22.10.2010

Есть ли шанс, что это реализовано в .NET? - если да, взгляните на Reactive Framework. Он обеспечивает очень элегантный способ обработки потоков и особенно отмены их на лету. - Кроме того, вы получаете очень расширяемую библиотеку расширения Linq для всевозможных вещей, таких как буферизация, мемоизация, Zip и т. Д.

Мы часто используем его для преобразования (и анализа), моделирования потоковых данных.

У Джеффа из команды Reative есть несколько хороших блогов о Потоковая и реальная здесь:

person Rune Baess    schedule 21.10.2010
comment
Ну... кажется, я забыл этот момент. ;-) Я делаю это на Mac, но хочу, чтобы код был переносимым. Таким образом, я хотел бы использовать только стандартную библиотеку или любые вызовы posix. - person iolo; 22.10.2010